How to use Serial data in IF statement to do something on Arduino Due

I am new to programming and have worked through this project until now. I am sending data to and from 6 esp32's via ESP_NOW with one connected to an Arduino Due. The data being sent is a series of bytes (ie: 65 1 1 1).

The data originates on a Nextion display and is transmitted to an ESP32 via Serial2, the ESP32 then uses ESP_NOW to transmit that data to another ESP32 that is connected to the Serial2 on the Due. I am able to print the information I transmit from the Nextion display on the serial monitor of the Due, I just cant seem to get it in a form that I can use to do something (like turn on an LED). I am using the same code on all the ESP32's and a modified version for the Due.

ESP32 Code:

#include <Arduino.h>
#include <esp_now.h>
#include <WiFi.h>

// Example to receive data with a start marker and length byte
// For ease of testing this uses upper-case characters A and B
//       for the request and response types
//       and Z for the start marker
//    this version saves all the bytes after the start marker
//       if the TYPE byte is wrong it aborts

const byte numBytes = 32;
byte receivedBytes[numBytes];
const byte typeBytePosition = 6; // Position after the start byte
const byte requestType = 0x65;
const byte requestLength = 7;

boolean newData = false;

int LED = 2;

// REPLACE WITH THE MAC Address of your receiver
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

// Variable to store if sending data was successful
String success;

struct __attribute__((packed)) dataPacket 
{
  byte EventID;
  byte PageID;
  byte ObjectID;
  byte StatusID;
} packet, *packetPtr;

struct button 
{
  byte buttonAddress[4]; //= {(byte) packet.EventID,(byte) packet.PageID,(byte) packet.ObjectID,(byte) packet.StatusID};
};

// const dataPacket onLoc1R = {0x65, 0x01, 0x01, 0x01};
// const dataPacket offLoc1R = {0x065, 0x01, 0x01, 0x00};
// const dataPacket onLoc1L = {0x65, 0x01, 0x02, 0x01};
// const dataPacket offLoc1L = {0x65, 0x01, 0x02, 0x00};

const button onLoc1R = {0x65, 0x01, 0x01, 0x01};
const button offLoc1R = {0x065, 0x01, 0x01, 0x00};
const button onLoc1L = {0x65, 0x01, 0x02, 0x01};
const button offLoc1L = {0x65, 0x01, 0x02, 0x00};

// Callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
{
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void emptyBuffer()
{
  for (byte n = 0; n < numBytes; n++)
  {
    receivedBytes[n] = 0;
  }
}

void recvBytesWithStartMarker()
{
  static boolean recvInProgress = false;
  static int ndx = -1;
  static byte numBytesReceived = 0;
  static byte mesgLen = 0;
  const byte startMarker = 0x65;
  byte rc;

  while (Serial2.available() > 0 && newData == false)
  {
    rc = Serial2.read();
    receivedBytes[numBytesReceived] = rc;
    numBytesReceived++;

    if (numBytesReceived > 33)
    {
      Serial.println("Error Rx : RESET   !!");
      Serial.println();
      emptyBuffer();
      numBytesReceived = 0;
      newData = false;
    }

    if (recvInProgress == true)
    {
      if (numBytesReceived == typeBytePosition)
      {
        ndx = 0; // enable saving of data (anticipate good data)
        if (rc == requestType)
        {
          mesgLen = requestLength;
        }
        else
        {
          recvInProgress = false; // abort - invalid request type
          ndx = -1;
        }
      }

      if (ndx >= 0)
      {
        ndx++;
      }

      if (numBytesReceived >= (mesgLen + typeBytePosition))
      { // got the whole message
        recvInProgress = false;
        newData = true;
      }
    }

    else if (rc == startMarker)
    {
      emptyBuffer();
      recvInProgress = true;
      numBytesReceived = 0;
      ndx = -1; // prevent counting valid bytes for the moment
    }
  }
}


void showNewData()
{
  if (newData == true)
  {
    Serial.println(WiFi.macAddress());
    Serial.print(requestType, HEX);
    packet.EventID = requestType;
    Serial.print(' ');
    for (byte n = 0; n < typeBytePosition; n++) // n < numBytes
    {
      if (n == 0)
      {
        packet.PageID = receivedBytes[n];
      }
      else if (n == 1)
      {
        packet.ObjectID = receivedBytes[n];
      }
      else if (n == 2)
      {
        packet.StatusID = receivedBytes[n];
      }
      Serial.print(receivedBytes[n], HEX);
      Serial.print(' ');
    }
    Serial.println();

    // Send message via ESP-NOW
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &packet, sizeof(packet));

    if (result == ESP_OK)
    {
      Serial.println("Sent with success");
    }
    else
    {
      Serial.println("Error sending the data");
    }

    newData = false;
  }
}

// Callback when data is received
void OnDataRecv(const uint8_t *mac, const uint8_t *data, int len)
{
  Serial.println(WiFi.macAddress());
  memcpy(&packet, data, sizeof(packet));

  Serial.printf("%x %x %x %x\n",(byte) packet.EventID,(byte) packet.PageID,(byte) packet.ObjectID,(byte) packet.StatusID);
  
  if (WiFi.macAddress() ==  "AC:67:B2:35:19:D8") // ESP32 connected to Arduino Due
  {
    // Serial2.write((byte) packet.EventID && (byte) packet.PageID && (byte) packet.ObjectID && (byte) packet.StatusID);
    Serial2.write((byte) packet.EventID);
    Serial2.write((byte) packet.PageID);
    Serial2.write((byte) packet.ObjectID);
    Serial2.write((byte) packet.StatusID);
  }
Serial.println();
}

void sendNewData()
{
  // Send message via ESP-NOW
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &packet, sizeof(packet));

  if (result == ESP_OK)
  {
    Serial.println("Sent with success");
  }
  else
  {
    Serial.println("Error sending the data");
  }
}

void setup()
{
  pinMode(LED, OUTPUT);
  Serial.begin(250000);
  Serial2.begin(115200);

  while (!Serial)
  {
    ;
  }

  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK)
  {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Once ESPNow is successfully Init, we will register for Send CB to get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);

  // Register peer
  esp_now_peer_info_t peerInfo;

  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;

  // Add peer

  if (esp_now_add_peer(&peerInfo) != ESP_OK)
  {
    Serial.println("Failed to add peer");
    return;
  }

  // Register for a callback function that will be called when data is received
  esp_now_register_recv_cb(OnDataRecv);

  //Setup has completed
  Serial.println("<ESP32 is ready>");

}

void loop()
{
  recvBytesWithStartMarker();
  showNewData();
}

And the Arduino Due code:

#include <Arduino.h>

const int BUFFER_SIZE = 3;
byte buf[BUFFER_SIZE];

int LED = 22;

struct __attribute__((packed)) dataPacket
{
  // byte EventID;
  byte PageID;
  byte ObjectID;
  byte StatusID;
} packet, *packetPtr;

// Attempt to create an array to group the bytes together for use in if statements
struct button
{
  byte buttonAddress[3];
};

// Definitions of variables wanted for the array if statements

button btnReceived = {packet.PageID, packet.ObjectID, packet.StatusID};

const button onLoc1R = {0x01, 0x01, 0x01};
const button offLoc1R = {0x01, 0x01, 0x00};
const button onLoc1L = {0x01, 0x02, 0x01};
const button offLoc1L = {0x01, 0x02, 0x00};


void OnDataRecv()
{
  int rxlen = Serial2.available(); // number of bytes available in Serial buffer

  if (rxlen > 0)
  {
    int rlen; // number of bytes to read

    if (rxlen > BUFFER_SIZE) // check if the data exceeds the buffer size
    {
      rlen = BUFFER_SIZE; // if yes, read BUFFER_SIZE bytes. The remaining will be read in the next time
    }
    else
    {
      rlen = rxlen;
    }
    while (rlen == BUFFER_SIZE)
    {
      // read the incoming bytes:
      rlen = Serial2.readBytes(buf, rlen);
      // rlen = Serial2.read();
      for (int i = 0; i < rlen; i++)
      {
        if (i == 0)
        {
          packet.PageID = buf[i];
        }
        else if (i == 1)
        {
          packet.ObjectID = buf[i];
        }
        else if (i == 2)
        {
          packet.StatusID = buf[i];
        }
        Serial.print(buf[i], HEX);
      }
      Serial.println();
    }
  }

  // This is the area I cant seem to work out: 

  if (btnReceived.buttonAddress == onLoc1L.buttonAddress)
  {
    digitalWrite(LED, HIGH);
    delay(100);
  }
  else
  {
    digitalWrite(LED, LOW);
  }
}

//

void setup()
{
  pinMode(LED, OUTPUT);
  Serial.begin(250000);
  Serial2.begin(115200);

  while (!Serial)
  {
    ;
  }

  Serial.println("Arduino Due Ready");
}

void loop()
{
  OnDataRecv();
}

Thanks in advance for any help or advice on how to accomplish this. Please let me know if there is something I need to change also, I basically have followed basic examples and modified lines of code to get it to work up to this point.

When I use serial, I use a sentence structure "<#,1,2,3,4>" or "<@,1,2,3,4>" are 2 examples of a sentence. The "<" is the begining of the sentence. The # is the instruction info. The "," is the data separator. The numbers is the data. The ">" is the end of the sentence. Upon receipt of the entire message, I pass the message onto a parser.

I appreciate your assistance! I am very new to programming, could you give me an example of how to set your suggestion up? I think what you are explaining is what I was trying to do with the struct __attribute__((packed)) dataPacket { byte EventID; byte PageID; byte ObjectID; byte StatusID; } packet, *packetPtr; and struct button { byte buttonAddress[4]; //= {(byte) packet.EventID,(byte) packet.PageID,(byte) packet.ObjectID,(byte) packet.StatusID}; }; I'm just not sure how to utilize the data as variables for the if statement to do something.

Thanks!!

Here is some code I use to receive serial data.

void fReceiveSerial_LIDAR( void * parameters  )
{
  bool BeginSentence = false;
  char OneChar;
  char *str;
  str = (char *)ps_calloc(300, sizeof(char) ); // put str buffer into PSRAM
  // log_i("Free PSRAM before String: %d", ESP.getFreePsram());
  for ( ;; )
  {
    EventBits_t xbit = xEventGroupWaitBits (eg, evtReceiveSerial_LIDAR, pdTRUE, pdTRUE, portMAX_DELAY);
    if ( LIDARSerial.available() >= 1 )
    {
      while ( LIDARSerial.available() )
      {
        OneChar = LIDARSerial.read();
        if ( BeginSentence )
        {
          if ( OneChar == '>')
          {
            if ( xSemaphoreTake( sema_ParseLIDAR_ReceivedSerial, xSemaphoreTicksToWait10 ) == pdTRUE )
            {
               xQueueOverwrite( xQ_LIDAR_Display_INFO, ( void * ) &str );
              xEventGroupSetBits( eg, evtParseLIDAR_ReceivedSerial );
              //
            }
            BeginSentence = false;
            break;
          }
          strncat( str, &OneChar, 1 );
        }
        else
        {
          if ( OneChar == '<' )
          {
            strcpy( str, ""); // clear string buffer
            BeginSentence = true; // found beginning of sentence
          }
        }
      } //  while ( LIDARSerial.available() )
    } //if ( LIDARSerial.available() >= 1 )
    xSemaphoreGive( sema_ReceiveSerial_LIDAR );
    //        log_i( "fReceiveSerial_LIDAR " );
    //        log_i(uxTaskGetStackHighWaterMark( NULL ));
  }
  free(str);
  vTaskDelete( NULL );
} //void fParseSerial( void * parameters  )

Here is some code I use to parse the received data.

void fParseLIDAR_ReceivedSerial ( void * parameters )
{
  // distribute received LIDAR info
  String sTmp = "";
  sTmp.reserve ( 20 );
  String sMessage = "";
  sMessage.reserve ( StringBufferSize300 );
  for ( ;; )
  {
    EventBits_t xbit = xEventGroupWaitBits (eg, evtParseLIDAR_ReceivedSerial, pdTRUE, pdTRUE, portMAX_DELAY) ;
    xQueueReceive ( xQ_LIDAR_Display_INFO, &sMessage, QueueReceiveDelayTime );
    int commaIndex = sMessage.indexOf(',');
    sTmp.concat ( sMessage.substring(0, commaIndex) );
    sMessage.remove( 0, (commaIndex + 1) ); // chop off begining of message
    if ( sTmp == "!" )
    {
      xSemaphoreGive ( sema_LIDAR_OK );
      //  Display info from LIDAR
      sLIDAR_Display_Info = sMessage;
    }
    if ( sTmp == "$" )
    {
      xEventGroupSetBits( eg1, evtResetWatchDogVariables );
    }
    if ( sTmp == "#")
    {
      xSemaphoreTake( sema_LIDAR_Alarm, xSemaphoreTicksToWait );
      sLIDAR_Alarm_info = sMessage;
      xSemaphoreGive( sema_LIDAR_Alarm );
      xEventGroupSetBits( eg, evtfLIDAR_Alarm );
    }
    sTmp = "";
    sMessage = "";
    xSemaphoreGive( sema_ParseLIDAR_ReceivedSerial );
  }
  vTaskDelete( NULL );
} // void fParseReceivedSerial ( void * parameters )

The above is an example of my use of the suggestion.

i think your recBytesWithStartMarker() would be better by reading a complete "line" of data, either knowing the # of bytes or looking for a terminator such as '\n'.

that code should simply append the received byte to a receive buffer and then process the buffer when the terminator is detected.

of course a startmarker can be used to force waiting for the first byte of the msg.

it looks like the code waits for a specific # of bytes which of course suggests the need for a start byte to resynchronise.

@Idahowalker - Thanks for the code examples, but when I tried to implement it in the code there are a number of undefined identifiers... Would you be able to show me the definitions so I can try to test or is it a library for the LIDAR device? Just trying to catch up!

ps_calloc
EventBits_t
xEventGroupWaitBits (eg, evtReceiveSerial_LIDAR, pdTRUE, pdTRUE, portMAX_DELAY)
LIDARSerial (I assume would be my Serial2 on the Due)
xSemaphoreTake( sema_ParseLIDAR_ReceivedSerial, xSemaphoreTicksToWait10 )
xQueueOverwrite( xQ_LIDAR_Display_INFO, ( void * ) &str );
xEventGroupSetBits( eg, evtParseLIDAR_ReceivedSerial );
xSemaphoreGive( sema_ReceiveSerial_LIDAR )
vTaskDelete( NULL )
StringBufferSize300
xQueueReceive ( xQ_LIDAR_Display_INFO, &sMessage, QueueReceiveDelayTime )
xSemaphoreGive ( sema_LIDAR_OK );
 xEventGroupSetBits( eg1, evtResetWatchDogVariables );
xSemaphoreTake( sema_LIDAR_Alarm, xSemaphoreTicksToWait );
sLIDAR_Alarm_info
xSemaphoreGive( sema_LIDAR_Alarm );
xEventGroupSetBits( eg, evtfLIDAR_Alarm );

Thanks!

@gcjr - I tried to grab the data all at once from the Nextion, but the way in which it sends data made it difficult to work with using the library they have. I wasn't able to get that to work, but learned that when I touch a button on the display it would give the Event ID, Page ID, and the Object ID followed by 3 0xFF (ie: 65 1 1 FF FF FF). I still had to send the Status ID to know if the button was on or off. There are many Event ID's according to the Nextion documentation, but I was only concerned with the ID 65. I decided to send only the info I needed from the Nextion to make my logic work. I found an example and ran with it (without the Nextion library) and knew I was only going to be looking for 3 bytes after the 65.

Once the ESP32 connected to the Due receives the info, I truncate the 65 so all that I'm left with is the Page ID, Object ID, and Status ID which is what I am trying to cram into an IF statement to do something. These ID's create a unique identifier for a specific location in which I need the Due to set up devices (pneumatic actuators).

I'm so new at this I have to start simple and work my way up...

If you have an example of what you are suggesting, I'd love to try to look it over to understand your suggestion better.

Thanks!!

freeRTOS is the built in OS of the ESP32.

ps_calloc, as noted in the ESP32 API, is a multi core safe wrapper for the malloc() functions.

LidarSerial is the designation that I use for one of the 2 available serial ports. OK, the ESP32 has 4 serial ports but it would be best if you left the other 2 alone. When you gain more knowledge of the use risk of the other 2 serial ports then you might consider using them.

StringBufferSize300 is a global variable not in the code I posted.

sLIDAR_Alarm_Info is a string global variable

You can use the ESP32 API and freeRTOS API to find out about those other things.

@Idahowalker - I remember reading about freeRTOS now that you mention it.

I also read that there are 4 serials available, but only Serial0 (I think that is the USB) and Serial2 are safe to use. the others had pins that were at a high state at boot which could damage connected devices (if I'm remembering correctly).

(It's the 4th line after " // distribute received LIDAR info"

I guess I need to include an ESP32 library for the Due (using PlatformIO) in order to take advantage and test your code?

I appreciate the help and I'm trying to keep up!

Oh, I thought you wanted ESP code.

Here is some code i wrote for the Due that does the serial thing





#include <uMT.h>
#include <Wire.h>
#include "TFMini.h"
#include <Servo.h>
#include <SimpleDHT.h>


//*************************************************
// scl pin 5, sda pin 4, vcc 3.3
// temperature, pressure, altitude, sealevelpressure
#define BMP085_ADDRESS 0x77  // I2C address of BMP085
#define BMP_Interval 65503
const unsigned char OSS = 0;  // Oversampling Setting
// Calibration values
int ac1;
int ac2;
int ac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
int b2;
int mb;
int mc;
int md;
// b5 is calculated in bmp085GetTemperature(...), this variable is also used in bmp085GetPressure(...)
// so ...Temperature(...) must be called before ...Pressure(...).
long b5;
//*********************************************
const String sSeperator = " ";
//*********************************************
Servo ServoLIDAR;
#define ServoLIDARPosit 1450
#define  byteServo_LIDAR_Pin 11
String sA = "";
//*********************************************
//X Axis servo
Servo X_Axis;
#define byteXaxisServoPin 9
#define iX_Posit90 1538 //using writeMicroseconds
int iX_HowMuch = iX_Posit90;
//Y Axis servo
Servo Y_Axis;
#define byteYaxisServoPin 10
#define iY_Posit90 1492 //using writeMicroseconds
int iY_HowMuch = iY_Posit90;
//*************************************************
TFMini tfmini;
// unsigned long lPreviousLIDAR_SequenceMillis = 0;
#define lLIDAR_SequenceInterval 50 // milliseconds
// 25mS is 40Hz
// 33mS ~30Hz
// 50mS 20Hz
// bool bBlankLIDAR = false;
//*************************************************
//
#define byteUnoDataReady 22
//*************************************************
// unsigned long lCurrentMillis = 0;
//*************************************************
//microwave motion detector= iMW
#define MWM_PINin 34
#define MWM_PINout 36
//*************************************************
// #define lLEDRateInterval 125 //milliseconds,  second
// unsigned long lPreviousLED_BlinkMillis = 0;
// bool bLedOnOff = false;
//*************************************************
String sMessageToSend;
String sPi;
//*************************************************
//*************************************************
// bool bRcveDone = false;
//*************************************************
// for DHT11,
//      VCC: 5V or 3V
//      GND: GND
//      DATA: 2
#define pinDHT11 2
SimpleDHT11 dht11(pinDHT11);
#define iDHT_Interval 60503
//*************************************************
#define iDoVolts_Interval 45007
//*************************************************
#define MINservo 1000
#define MAXservo 2000
#define SerialBaudRate 9600
#define Serial2BaudRate 115200
#define StringBufferSize 50
//*************************************************
// bool bTask2Started = false;
//*************************************************
#define EVENT_A  0x0001
TaskId_t iEvtID_A;
//
#define EVENT_B  0x0002
TaskId_t iEvtID_B;
//
#define EVENT_C  0x0003
TaskId_t iEvtID_C;
//
#define EVENT_D  0x0004
TaskId_t iEvtID_D;
//
#define EVENT_E  0x0005
TaskId_t iEvtID_E;
//
#define EVENT_F  0x0006
TaskId_t iEvtID_F;
//*************************************************
#define  SEM_ID_01   1   // Semaphore id
#define  SEM_ID_02   2   // Semaphore id
#define  SEM_ID_03   3   // Semaphore id
#define  SEM_ID_04   4   // Semaphore id
// #define TIMEOUT_A
//*************************************************
Stream* stream2Ptr;
//*************************************************


void setup()
{

  pinMode(40, OUTPUT);
  digitalWrite( 40, LOW );
  ////
  pinMode(byteUnoDataReady, OUTPUT);//setup interrupt pin as output
  digitalWrite(byteUnoDataReady, LOW);//set state initial
  ////
  Serial1.begin(TFMINI_BAUDRATE);
  // Initialize the TFMini LIDAR
  tfmini.begin(&Serial1);
  // Initialize single measurement mode with external trigger
  tfmini.setSingleScanMode();
  ////
  Serial2.begin( Serial2BaudRate );
  stream2Ptr = &Serial2;
  ////
  pinMode(MWM_PINin, INPUT);
  pinMode(MWM_PINout, OUTPUT);
  ////
  pinMode(LED_BUILTIN, OUTPUT);//blink LED at pin 13
  ////
  analogReadResolution( 12 );
  ////
  ServoLIDAR.attach( byteServo_LIDAR_Pin, MINservo, MAXservo );  // attaches the servo pin to the servo object
  ServoLIDAR.writeMicroseconds(ServoLIDARPosit);//sets initial posit
  ////
  X_Axis.attach( byteXaxisServoPin, MINservo, MAXservo );
  X_Axis.writeMicroseconds( iX_Posit90 );
  ////
  Y_Axis.attach( byteYaxisServoPin, MINservo, MAXservo );
  Y_Axis.writeMicroseconds( iY_Posit90 );
  ////
  Serial.begin(SerialBaudRate);
  ////
  // allocate a buffer in memory for these strings
  sMessageToSend.reserve( StringBufferSize );
  sPi.reserve( StringBufferSize );
  ////
  Wire.begin();
  bmp085Calibration();
  ////
  ADC->ADC_MR |= 0x80;  //set free running mode on ADC
  REG_ADC_MR = (REG_ADC_MR & 0xFFF0FFFF) | 0x00020000; // adc start up value
  // ADC->ADC_CHER = 0x80; //enable ADC on pin A0
  ////
  Kernel.Kn_Start();

} // setup()



void loop()
{
  // if ( !bTask2Started )
  // {
  Errno_t error;

  TaskId_t fC_P;
  // fCheck_Pressure
  error = Kernel.Tk_CreateTask(fCheck_Pressure, fC_P);
  if ( error != E_SUCCESS )
  {
    fKernalError( "fCheck_Pressure", error );
  }
  ////
  // bTask2Started = !bTask2Started;
  ////
  Kernel.Tk_StartTask(fC_P);
  // fCheck_TH
  TaskId_t fC_TH;
  error = Kernel.Tk_CreateTask(fCheck_TH, fC_TH);
  if ( error != E_SUCCESS )
  {
    fKernalError( "fCheck_TH", error );
  }
  Kernel.Tk_StartTask( fC_TH ) ;
  // fCheckInputVoltage
  TaskId_t fDoVolts;
  error = Kernel.Tk_CreateTask( fCheckInputVoltage, fDoVolts );
  if ( error != E_SUCCESS )
  {
    fKernalError( "fCheckInputVoltage", error );
  }
  Kernel.Tk_StartTask( fDoVolts ) ;
  //  fDoLIDAR
  TaskId_t fLIDAR;
  error = Kernel.Tk_CreateTask( fDoLIDAR, fLIDAR );
  if ( error != E_SUCCESS )
  {
    fKernalError( "fDoLIDAR", error );
  }
  Kernel.Tk_StartTask( fLIDAR ) ;
  //    //
  //    ////////////////////////////
  //    ////////////////////////////
  //    ////////////////////////////
  // fReadSerial
  error = Kernel.Tk_CreateTask( fReadSerial, iEvtID_A );
  Kernel.Tk_StartTask( iEvtID_A );
  // fDO_bRcveDone
  error = Kernel.Tk_CreateTask( fDO_bRcveDone, iEvtID_B );
  Kernel.Tk_StartTask( iEvtID_B );
  // fTweakServoX
  error = Kernel.Tk_CreateTask( fTweakServoX, iEvtID_C );
  Kernel.Tk_StartTask( iEvtID_C );
  // fTweakServoY
  error = Kernel.Tk_CreateTask( fTweakServoY, iEvtID_D );
  Kernel.Tk_StartTask( iEvtID_D );
  // fLIDAR_ServoAspectChange
  error = Kernel.Tk_CreateTask( fLIDAR_ServoAspectChange, iEvtID_E );
  Kernel.Sm_Release( SEM_ID_02 ); // release a single SEMAPHORE token
  Kernel.Sm_Release( SEM_ID_03 );
  Kernel.Tk_StartTask( iEvtID_E );
  // fSendOut_SEMAPHORE
  error = Kernel.Tk_CreateTask( fSendOut_SEMAPHORE, iEvtID_F );
  Kernel.Sm_Release( SEM_ID_01 ); // release a single SEMAPHORE token
  Kernel.Tk_StartTask( iEvtID_F );
  ////////////////////////////////////////
  ////////////////////////////////////////
  ////////////////////////////////////////
  // }
  for ( ;; )
  {
    if ( stream2Ptr->available() >= 1 )
    // if (Serial2.available() >= 1)
    {
      Kernel.Ev_Send(iEvtID_A, EVENT_A);
      Kernel.Sm_Claim(SEM_ID_04, uMT_WAIT); // stop and wait for serial to be received and release of SEMAPHORE token
    }  //  serial available
    Kernel.Tk_Yield();
  }
} // loop
//******************************************
//******************************************
//******************************************
//
void fKernalError(String sTask, unsigned error)
{
  Serial.print( " Tk_CreateTask(): " + sTask + " Failure! - returned " );
  Serial.println( error );
  Serial.flush();
  Kernel.isr_Kn_FatalError();
} // void fKernalError()
//******************************************
//   digitalWriteDirect / digitalReadDirect
//******************************************
// example: digitalWriteDirect(13, HIGH)
inline void digitalWriteDirect(int pin, boolean val)
{
  if (val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
  else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}
// example: digitalReadDirect(12)
inline int digitalReadDirect(int pin)
{
  return !!(g_APinDescription[pin].pPort -> PIO_PDSR & g_APinDescription[pin].ulPin);
}
//******************************************
//
//******************************************
//
//******************************************
//******************************************
///
//******************************************
void fDoLIDAR()
{
  //
  long iLIDAR_Distance = 0;
  long iLIDAR_Strength = 0;
  String sMsgToSend;
  String s_cm = "cm ";
  sMsgToSend.reserve( 16 );
  while (1)
  {
    Kernel.Tm_WakeupAfter( lLIDAR_SequenceInterval );   // Wake up after ... milliseconds
    Kernel.Sm_Claim(SEM_ID_02, uMT_WAIT); // // stop lidar servo
    Kernel.Sm_Claim(SEM_ID_03, uMT_WAIT); // stop x y servo
    //    if ( !bBlankLIDAR )
    //    {
    if ( digitalReadDirect( MWM_PINin ) )
      // if ( digitalRead( MWM_PINin ) == 1 )
    {
      digitalWriteDirect( MWM_PINout, HIGH );
      tfmini.externalTrigger();
      iLIDAR_Distance = tfmini.getDistance();
      iLIDAR_Strength = tfmini.getRecentSignalStrength();
      if (iLIDAR_Distance < 600)
      {
        // Serial.println( "TF Mini distance " + String(iLIDAR_Distance) + s_cm + " strength " + String(iLIDAR_Strength ) );
        // Serial.flush();
        sMsgToSend.concat( s_cm + String(iLIDAR_Distance) + " " + String(iLIDAR_Strength ) );
        Kernel.Sm_Claim(SEM_ID_01, uMT_WAIT); // // claim a single SEMAPHORE token
        sMessageToSend = sMsgToSend;
        Kernel.Ev_Send(iEvtID_F, EVENT_F);  // trigger fSendOut_SEMAPHORE + consume a single SEMAPHORE token
        sMsgToSend = "";
      }
    }
    else
    {
      digitalWriteDirect( MWM_PINout, LOW );
    }
    Kernel.Sm_Release( SEM_ID_02 ); // release a single SEMAPHORE token
    Kernel.Sm_Release( SEM_ID_03 );
  }
}
//******************************************
//      bmp085 functions
//******************************************
// Calculate pressure given up
// calibration values must be known
// b5 is also required so bmp085GetTemperature(...) must be called first.
// Value returned will be pressure in units of Pa.
long bmp085GetPressure(unsigned long up)
{
  long x1, x2, x3, b3, b6, p;
  unsigned long b4, b7;

  b6 = b5 - 4000;
  // Calculate B3
  x1 = (b2 * (b6 * b6) >> 12) >> 11;
  x2 = (ac2 * b6) >> 11;
  x3 = x1 + x2;
  b3 = (((((long)ac1) * 4 + x3) << OSS) + 2) >> 2;

  // Calculate B4
  x1 = (ac3 * b6) >> 13;
  x2 = (b1 * ((b6 * b6) >> 12)) >> 16;
  x3 = ((x1 + x2) + 2) >> 2;
  b4 = (ac4 * (unsigned long)(x3 + 32768)) >> 15;

  b7 = ((unsigned long)(up - b3) * (50000 >> OSS));
  if (b7 < 0x80000000)
    p = (b7 << 1) / b4;
  else
    p = (b7 / b4) << 1;

  x1 = (p >> 8) * (p >> 8);
  x1 = (x1 * 3038) >> 16;
  x2 = (-7357 * p) >> 16;
  p += (x1 + x2 + 3791) >> 4;

  return p;
}
// Calculate temperature given ut.
// Value returned will be in units of 0.1 deg C
short bmp085GetTemperature(unsigned int ut)
{
  long x1, x2;

  x1 = (((long)ut - (long)ac6) * (long)ac5) >> 15;
  x2 = ((long)mc << 11) / (x1 + md);
  b5 = x1 + x2;

  return ((b5 + 8) >> 4);
}
// Read the uncompensated pressure value
unsigned long bmp085ReadUP()
{
  unsigned char msb, lsb, xlsb;
  unsigned long up = 0;

  // Write 0x34+(OSS<<6) into register 0xF4
  // Request a pressure reading w/ oversampling setting
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(0xF4);
  Wire.write(0x4 + (OSS << 6));
  Wire.endTransmission();

  // Wait for conversion, delay time dependent on OSS
  // delay(2 + (3 << OSS));
  Kernel.Tm_WakeupAfter( 2 + (3 << OSS) );
  // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(0xF6);
  Wire.endTransmission();
  Wire.requestFrom(BMP085_ADDRESS, 3);

  // Wait for data to become available
  while (Wire.available() < 3)
    ;
  msb = Wire.read();
  lsb = Wire.read();
  xlsb = Wire.read();
  up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8 - OSS);

  return up;
}
// Read the uncompensated temperature value
unsigned int bmp085ReadUT()
{
  unsigned int ut;
  // Write 0x2E into Register 0xF4
  // This requests a temperature reading
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(0xF4);
  Wire.write(0x2E);
  Wire.endTransmission();
  // Wait at least 4.5ms
  Kernel.Tm_WakeupAfter( 5 );
  // delay(5);
  // Read two bytes from registers 0xF6 and 0xF7
  ut = bmp085ReadInt(0xF6);
  return ut;
}
// Stores all of the bmp085's calibration values into global variables
// Calibration values are required to calculate temp and pressure
// This function should be called at the beginning of the program
void bmp085Calibration()
{
  ac1 = bmp085ReadInt(0xAA);
  ac2 = bmp085ReadInt(0xAC);
  ac3 = bmp085ReadInt(0xAE);
  ac4 = bmp085ReadInt(0xB0);
  ac5 = bmp085ReadInt(0xB2);
  ac5 = bmp085ReadInt(0xB2);
  ac6 = bmp085ReadInt(0xB4);
  b1 = bmp085ReadInt(0xB6);
  b2 = bmp085ReadInt(0xB8);
  mb = bmp085ReadInt(0xBA);
  mc = bmp085ReadInt(0xBC);
  md = bmp085ReadInt(0xBE);
}
// Read 2 bytes from the BMP085
// First byte will be from 'address'
// Second byte will be from 'address'+1
int bmp085ReadInt(unsigned char address)
{
  unsigned char msb, lsb;

  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(address);
  Wire.endTransmission();

  Wire.requestFrom(BMP085_ADDRESS, 2);
  while (Wire.available() < 2);
  msb = Wire.read();
  lsb = Wire.read();

  return (int) msb << 8 | lsb;
}
// Read 1 byte from the BMP085 at 'address'
char bmp085Read(unsigned char address)
{
  unsigned char data;

  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(address);
  Wire.endTransmission();

  Wire.requestFrom(BMP085_ADDRESS, 1);
  while (!Wire.available())
    ;

  return Wire.read();
}
void fCheck_Pressure()
{
  Errno_t error;
  // TimerId_t TmId;
  String sMsgToSend;
  sMsgToSend.reserve( StringBufferSize );
  short bmp_temperature;
  long bmp_pressure;
  // float bmp_altitude;
  //Serial.println( "do fCheck_Pressure" );
  //Serial.flush();
  while (1)
  {
    error = Kernel.Tm_WakeupAfter( BMP_Interval );   // Wake up after ... seconds
    if (error != E_SUCCESS)
    {
      Serial.print(F(" WakeupAfter(): Tm_WakeupAfter() Failure! - returned "));
      Serial.print((unsigned)error);
      Serial.flush();
      break;
    }
    if ( digitalReadDirect( MWM_PINin ) == 0 )
    {
      sMsgToSend = "Pa ";
      // Serial.println( "do fCheck_Pressure3" );
      // Serial.flush();
      bmp_temperature = bmp085GetTemperature(bmp085ReadUT());
      bmp_pressure = bmp085GetPressure(bmp085ReadUP());
      // sMsgToSend.concat( String(bmp_temperature) + sSeperator );
      sMsgToSend.concat( String(bmp_pressure) + sSeperator );
      // sMsgToSend.concat( String(bmp_altitude) + sSeperator );
      // Serial.println( sMsgToSend );
      // Serial.flush();
      Kernel.Sm_Claim(SEM_ID_01, uMT_WAIT); // // claim a single SEMAPHORE token
      sMessageToSend = sMsgToSend;
      Kernel.Ev_Send(iEvtID_F, EVENT_F);  // trigger fSendOut_SEMAPHORE + consume a single SEMAPHORE token
      sMsgToSend = "";
    }
  }
  //  // bTask2Started = false;
}
//******************************************
void fCheck_TH()
{
  // TimerId_t TmId1;
  String sMsgToSend;
  byte temperature = 0;
  byte humidity = 0;
  String sTH = "TH ";
  sMsgToSend.reserve( 16 );
  while (1)
  {
    Kernel.Tm_WakeupAfter( iDHT_Interval );   // Wake up after ... seconds
    if ( digitalReadDirect( MWM_PINin ) == 0 )
    {
      dht11.read(&temperature, &humidity, NULL);
      sMsgToSend = sTH;
      sMsgToSend.concat( String(temperature) + sSeperator + String(humidity) );
      // Serial.println( sMsgToSend );
      // Serial.flush();
      Kernel.Sm_Claim(SEM_ID_01, uMT_WAIT); // // claim a single SEMAPHORE token
      sMessageToSend = sMsgToSend;
      Kernel.Ev_Send(iEvtID_F, EVENT_F);  // trigger fSendOut_SEMAPHORE + consume a single SEMAPHORE token
      sMsgToSend = "";
    }
  } // while (1)
}
//******************************************
//
//******************************************
void fDO_bRcveDone()
{
  String sAspectCng = "AspectCng";
  String s_gX = "gX";
  String s_gY = "gY";
  Event_t  eventoutB;
  while (1)
  {
    Kernel.Ev_Receive(EVENT_B, uMT_ANY, &eventoutB);
    digitalWriteDirect( 40, HIGH );
    sPi.replace( "/", " " );
    // sPi.trim();
    // Serial.println(sPi + " bRcveDone" );
    // Serial.flush();
    ////
    if (sPi.substring(0, 9) == sAspectCng)
    {
      // Serial.println(sPi + " rcvd" );
      sA = sPi.substring(9);
      Kernel.Ev_Send(iEvtID_E, EVENT_E);
      // Serial.println("AspectString " + sA );
      // Serial.flush();
    }
    ////
    // Serial.println( sPi.substring(0, 2) );
    if ( sPi.substring(0, 2) == s_gX )
    {
      // Serial.println(sPi);
      // Serial.flush();
      // stop lidar if lidar has token do not wait for freed token skip torque attempt
      if ( Kernel.Sm_Claim(SEM_ID_03, uMT_NOWAIT) != E_WOULD_BLOCK )
      {
        iX_HowMuch = sPi.substring(3).toInt();
        Kernel.Ev_Send(iEvtID_C, EVENT_C);
      }
    }
    ////
    if ( sPi.substring(0, 2) == s_gY )
    {
      // Serial.println(sPi);
      // Serial.flush();
      if ( Kernel.Sm_Claim(SEM_ID_03, uMT_NOWAIT) != E_WOULD_BLOCK )
      {
        iY_HowMuch = sPi.substring(3).toInt();
        Kernel.Ev_Send(iEvtID_D, EVENT_D);
      }
    }
    sPi = "";
    digitalWriteDirect( 40, LOW );
  }
}
//******************************************
//
//******************************************
void fReadSerial()
{
  //
  Event_t  eventoutA;
  char OneChar;
  while (1)
  {
    // Event_t  eventoutA;
    Kernel.Ev_Receive(EVENT_A, uMT_ANY, &eventoutA);
    ////
    while ( stream2Ptr->available() )
    {
      OneChar = stream2Ptr->read();
      if ( (OneChar != '\n') )
      {
        //Serial.println(sPi);
        sPi.concat( OneChar );
        // Serial.println(sPi + " char" );
        // Serial.flush();
        digitalWrite( 40, LOW );
      } // if ( (OneChar != '\n') )
      else
      {
        Kernel.Ev_Send(iEvtID_B, EVENT_B);  // trigger fDO_bRcveDone
        // bRcveDone = true;
        // Serial.println( "bRcveDone set true" );
        Serial.flush();
        break;
      } // if ( (chrOne != '\n') ) else
    } // while ( Serial2.available() )
    Kernel.Sm_Release( SEM_ID_04); // release serial avaible trigger in loop
  } //  while (1)
}
//******************************************
//
/*
  1000 u sec to 2000 u sec limit = 90 degrees of travel +/-45 deg
  1K = 45 to 2K = 135

*/
//******************************************
void fTweakServoX()
{
  Event_t  eventoutC;
  while (1)
  {
    Kernel.Ev_Receive(EVENT_C, uMT_ANY, &eventoutC);
    X_Axis.writeMicroseconds( iX_HowMuch );
    Kernel.Sm_Release( SEM_ID_03 );
  }
}
void fTweakServoY()
{
  Event_t  eventoutD;
  while (1)
  {
    Kernel.Ev_Receive(EVENT_D, uMT_ANY, &eventoutD);
    // Serial.println( "iY_HowMuch = " + String(iY_HowMuch) );
    Y_Axis.writeMicroseconds( iY_HowMuch );
    Kernel.Sm_Release( SEM_ID_03 );
  }
}
//******************************************
//  send data to RPi
//******************************************
void fSendOut_SEMAPHORE()
{
  Event_t  eventoutF;
  while (1)
  {
    Kernel.Ev_Receive(EVENT_F, uMT_ANY, &eventoutF);
    // Serial.println("fSendOut_SEMAPHORE 0 " + sMessageToSend );
    // Serial1.flush();
    if ( sMessageToSend.length() >= 2 )
    {
      // Serial.println("fSendOut_SEMAPHORE 1 " + sMessageToSend );
      // Serial.flush();
      stream2Ptr->println( sMessageToSend );
      digitalWrite(byteUnoDataReady, HIGH);//TRIGGER RPi3 to read data
      // delay( .05 );
      Kernel.Tm_WakeupAfter( 50 );
      // Serial.println( sMessageToSend.length() );
      // Serial.println("fSendOut_SEMAPHORE " + sMessageToSend );
      // Serial.flush();
      digitalWrite(byteUnoDataReady, LOW);//reset
      sMessageToSend = "";
      Kernel.Sm_Release( SEM_ID_01 ); // release a single SEMAPHORE token
    }
  }
}
//****************************************************
//
//****************************************************
void fLIDAR_ServoAspectChange()
{

  char fltBuff[32];
  String sAspectComplete = "AspectComplete";
  Event_t  eventoutE;
  String sMsgToSend;
  sMsgToSend.reserve( 16 );
  //
  while (1)
  {
    Kernel.Ev_Receive(EVENT_E, uMT_ANY, &eventoutE);
    Kernel.Sm_Claim(SEM_ID_02, uMT_WAIT); // // claim a single SEMAPHORE token.
    if ( sA.length() < 8 )
    {
      // bBlankLIDAR = true;
      sA.toCharArray(fltBuff, sizeof(fltBuff));
      float fltAspect = atof(fltBuff);
      //
      if (fltAspect > 900.00f)
      {
        // Serial.println("AspectString " + String(sA));
        // Serial.flush();
        ServoLIDAR.writeMicroseconds(fltAspect);
      }
      //delay(20);
      // Serial.println( "AspectComplete " + sA );
      // Serial.flush();
    }
    else
    {
      Serial.println("AspectString reject " + String(sA));
    }
    // Serial.println( "fLIDAR_ServoAspectChange " + sMessageToSend );
    // Serial.flush();
    Kernel.Sm_Release( SEM_ID_02 ); // release a single SEMAPHORE token
    Kernel.Sm_Claim(SEM_ID_01, uMT_WAIT); // // claim a single SEMAPHORE token
    sMsgToSend = sAspectComplete;
    sMessageToSend = sMsgToSend;
    Kernel.Ev_Send(iEvtID_F, EVENT_F);  // trigger fSendOut_SEMAPHORE + consume a single SEMAPHORE token
    // bBlankLIDAR = false;
    //
  }
}
//******************************************
//
//******************************************
void fCheckInputVoltage()
{
  String sMsgToSend;
  String s_Volts = "VOLT ";
  sMsgToSend.reserve( 16 );
  while (1)
  {
    Kernel.Tm_WakeupAfter( iDoVolts_Interval );   // Wake up after ... seconds
    // Serial.println( "dovolt awake1" );
    // Serial.flush();
    if ( digitalReadDirect( MWM_PINin ) == 0 )
    {
      sMsgToSend = s_Volts;
      sMsgToSend.concat(String(analogRead(A0)));
      // Serial.println( "fCheckInputVoltage" + sMsgToSend );
      // Serial.flush();
      Kernel.Sm_Claim(SEM_ID_01, uMT_WAIT); // // claim a single SEMAPHORE token
      sMessageToSend = sMsgToSend;
      Kernel.Ev_Send(iEvtID_F, EVENT_F);  // trigger fSendOut_SEMAPHORE + consume a single SEMAPHORE token
      sMsgToSend = "";
      // Kernel.Sm_Release(SEM_ID_02);
    }
  }
}
//******************************************
//
//*************************************************

The code I use for doing the serial port thing, I wrote originally for the Due and ported it to the ESP32.

@Idahowalker - I thought there may have been a miscommunication on my part... I really appreciate the help!

This looks impressive. I'll try to look it over and get back to you if I can't figure something out!

Check out my page on Arduino to Arduino via Serial which has a simple CSV send/receive/decode example
As well as other examples.