Looping for a serial transfer but run code if not available

Basically I have made use of this code to add a ESP32Cam to the master (RX).

Tx ESP32Cam

#define DEBUG_ESP              //comment out to deactivate debug console

#ifdef DEBUG_ESP
  #define pDBGln(x) Serial.println(x)
  #define pDBG(x)   Serial.print(x)
#else 
  #define pDBG(...)
  #define pDBGln(...)
#endif

#include "esp_camera.h"
#include "Arduino.h"
#include "soc/soc.h"           // Disable brownour problems
#include "soc/rtc_cntl_reg.h"  // Disable brownour problems
#include "driver/rtc_io.h"
#include "SerialTransfer.h"

// Pin definition for CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

SerialTransfer myTransfer;
HardwareSerial Comm(1);
struct img_meta_data{
  uint16_t counter;
  uint16_t imSize;
  uint16_t numLoops;
  uint16_t sizeLastLoop;
} ImgMetaData;
const uint16_t PIXELS_PER_PACKET = MAX_PACKET_SIZE - sizeof(ImgMetaData);

void setup(){
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
 
  Serial.begin(115200);                     // Define and start serial monitor
  // 115200,256000,512000,962100
  Comm.begin(962100, SERIAL_8N1,15,14);     //, Comm_Txd_pin, Comm_Rxd_pin); // Define and start Comm serial port
  myTransfer.begin(Comm);
 
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
 
//  if(psramFound()){
//    config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
//    config.jpeg_quality = 10;
//    config.fb_count = 2;
//  } else {
//    config.frame_size = FRAMESIZE_SVGA;
//    config.jpeg_quality = 12;
//    config.fb_count = 1;
//  }

    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
 
  // Init Camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK){
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }
}

void loop(){
  uint16_t startIndex = 0;
  camera_fb_t * fb = NULL;
  //Take Picture with Camera
  fb = esp_camera_fb_get(); 
   
  ImgMetaData.imSize       = fb->len;                             //sizeof(myFb);
  ImgMetaData.numLoops     = (fb->len / PIXELS_PER_PACKET) + 1;   //(sizeof(myFb)/PIXELS_PER_PACKET) + 1; 
  ImgMetaData.sizeLastLoop = fb->len % PIXELS_PER_PACKET;         //(sizeof(myFb)%PIXELS_PER_PACKET);

  for(ImgMetaData.counter=1; ImgMetaData.counter<=ImgMetaData.numLoops; ImgMetaData.counter++){
    myTransfer.txObj(ImgMetaData, sizeof(ImgMetaData));
    //printStructBuf();
    stuffPixels(fb->buf, startIndex, sizeof(ImgMetaData), PIXELS_PER_PACKET);
    //stuffPixels(myFb, startIndex, sizeof(ImgMetaData), PIXELS_PER_PACKET);
    //printStructBuf();   
    myTransfer.sendData(MAX_PACKET_SIZE);
     
    pDBGln(F("Sent:"));
    pDBG(F("img.counter: "));      pDBGln((uint16_t)((myTransfer.txBuff[1] << 8) | myTransfer.txBuff[0]));
    pDBG(F("img.imSize: "));       pDBGln((uint16_t)((myTransfer.txBuff[3] << 8) | myTransfer.txBuff[2]));
    pDBG(F("img.numLoops: "));     pDBGln((uint16_t)((myTransfer.txBuff[5] << 8) | myTransfer.txBuff[4]));
    pDBG(F("img.sizeLastLoop: ")); pDBGln((uint16_t)((myTransfer.txBuff[7] << 8) | myTransfer.txBuff[6]));

    startIndex += PIXELS_PER_PACKET;    
    delay(100);
    //printBuf();  
  }
  esp_camera_fb_return(fb);   //clear camera memory
  delay(10000);
}

void printStructBuf(){
  pDBG(F("Internal Struct: { "));
  for (uint16_t k=0; k<sizeof(ImgMetaData); k++){
    pDBG(myTransfer.txBuff[k]);
    if (k<(sizeof(ImgMetaData)-1))
      pDBG(F(", "));
    else
      pDBGln(F(" }"));
  }
}

void printBuf(){
  pDBG(F("Pixel Values: { "));
  for (uint16_t k=8; k<MAX_PACKET_SIZE; k++){
    pDBG(myTransfer.txBuff[k]);
    if (k < (MAX_PACKET_SIZE - 1))
      pDBG(F(", "));
    else
      pDBGln(F(" }"));
  }
  pDBGln();
}

void stuffPixels(const uint8_t * pixelBuff, const uint16_t &bufStartIndex, const uint16_t &txStartIndex, const uint16_t &len){
  uint16_t txi = txStartIndex;
  for (uint16_t i=bufStartIndex; i<(bufStartIndex + len); i++)  {
    myTransfer.txBuff[txi] = pixelBuff[i];
    txi++;
  }
}

RX Master

/*Receives picture via serial and saves to ftp*/

#define DEBUG_ESP              //comment out to deactivate debug console

#ifdef DEBUG_ESP
  #define pDBGln(x) Serial.println(x)
  #define pDBG(x)   Serial.print(x)
#else 
  #define pDBG(...)
  #define pDBGln(...)
#endif

#include "SerialTransfer.h"
SerialTransfer myTransfer;
struct img_meta_data{
  uint16_t counter;
  uint16_t imSize;
  uint16_t numLoops;
  uint16_t sizeLastLoop;
} ImgMetaData;
uint16_t packetCounter=1;
uint16_t bufferPointer=0;
char tempImageBuffer[32000];

#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
// Variables to save date and time
String formattedDate;
String dayStamp;
String timeStamp;

// FTP Client Lib
#include "ESP32_FTPClient.h"

// Your WiFi credentials.
char ssid[] = "myssid";
char pass[] = "mypass";

// FTP Server credentials
char ftp_server[] = "192.168.0.1";
char ftp_user[]   = "pcborges"; 
char ftp_pass[]   = "mypass";

// picture name
String picPrefix ="";
String pic_name;  

// Connection timeout;
#define CON_TIMEOUT   10*1000                     // milliseconds

ESP32_FTPClient ftp(ftp_server, ftp_user, ftp_pass);

void setup(){
  //Serial.begin(Baud Rate, Data Protocol, Txd pin, Rxd pin);
  Serial.begin(115200);                                                     // Define and start serial monitor
  // 115200,256000,512000,962100
  Serial2.begin(962100, SERIAL_8N1); //Receiver_Txd_pin, Receiver_Rxd_pin); // Define and start Receiver serial port
  myTransfer.begin(Serial2);

  WiFi.begin(ssid, pass);
  pDBGln("Connecting Wifi...");
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      pDBG(".");
  }
  pDBGln("");
  pDBG("IP address: ");
  pDBGln(WiFi.localIP());
  pDBGln();

  // Initialize a NTPClient to get time
  timeClient.begin();
  // Set offset time in seconds to adjust for your timezone, for example:
  // GMT +1 = 3600, GMT +8 = 28800, GMT -1 = -3600, GMT 0 = 0
  timeClient.setTimeOffset(3600*-3);  
}

void loop(){
  if(myTransfer.available())  {
    myTransfer.rxObj(ImgMetaData, sizeof(ImgMetaData));
    pDBG("Struct Data: ");
    pDBG(ImgMetaData.counter);
    pDBG(", ");
    pDBG(ImgMetaData.imSize);
    pDBG(", ");  
    pDBG(ImgMetaData.numLoops);
    pDBG(", ");
    pDBG(ImgMetaData.sizeLastLoop);
    pDBG(", PacketCounter: ");
    pDBGln(packetCounter);  

    if(ImgMetaData.counter==1){  
      copyToImageBuff(MAX_PACKET_SIZE-sizeof(ImgMetaData));
    }else{
      if(ImgMetaData.counter==packetCounter){  
        if(packetCounter<ImgMetaData.numLoops){        
          copyToImageBuff(MAX_PACKET_SIZE-sizeof(ImgMetaData));
        }else if(ImgMetaData.counter==packetCounter){
          copyToImageBuff(ImgMetaData.sizeLastLoop);     
        }
      }
    }
 
    if(packetCounter>ImgMetaData.numLoops){  
      pic_name  = picPrefix;
      pic_name += getDateTime() + ".jpg";  
      FTP_upload();     
      packetCounter=1;
      bufferPointer=0;
      delay(2000);
      //while(1){}
    }  

  }else if(myTransfer.status < 0) { 
    pDBG("ERROR: ");
    if(myTransfer.status == -1)
      pDBGln(F("CRC_ERROR"));
    else if(myTransfer.status == -2)
      pDBGln(F("PAYLOAD_ERROR"));
    else if(myTransfer.status == -3)
      pDBGln(F("STOP_BYTE_ERROR"));
  }
}
  

void copyToImageBuff(uint16_t dataLenght){
  for(int y=0;y<dataLenght;y++){
    tempImageBuffer[bufferPointer+y] = myTransfer.rxBuff[y+sizeof(ImgMetaData)];
  } 
  bufferPointer+=dataLenght;
  packetCounter++;  

  pDBG("dataLenght: ");
  pDBG(dataLenght);  
  pDBG(", bufferPointer: ");
  pDBGln(bufferPointer);
}

void printBuf(char localBuff){
  pDBG(F("Pixel Values: { "));
  for (uint16_t k=0; k<sizeof(myTransfer.rxBuff); k++){
    pDBG(myTransfer.rxBuff[k]);
    if (k < (sizeof(myTransfer.rxBuff) - 1))
      pDBG(F(", "));
    else
      pDBGln(F(" }"));
  }
}

void FTP_upload(){
  pDBG("Uploading via FTP: "); 
  ftp.OpenConnection();
  //ftp.ChangeWorkDir("/public_html/zyro/");
  //Create a file and write the image data to it;
  ftp.InitFile("Type I");
  const char *f_name = pic_name.c_str();
  ftp.NewFile( f_name ); 
  pDBGln( f_name );    
  ftp.WriteData((unsigned char*)tempImageBuffer, ImgMetaData.imSize);
  ftp.CloseFile();
  // Breath, withouth delay URL failed to update.
  pDBGln("Done... Waiting next transfer...");
  delay(100);
}

String getDateTime(){
  String curDateTime="";

  while(!timeClient.update()) {
    timeClient.forceUpdate();
  }
  // The formattedDate comes with the following format:
  // 2018-05-28T16:00:13Z
  // We need to extract date and time
  formattedDate = timeClient.getFormattedDate();

  #ifdef DEGUB_ESP
    // Extract date
    int splitT = formattedDate.indexOf("T");
    dayStamp = formattedDate.substring(0, splitT);
    // Extract time
    timeStamp = formattedDate.substring(splitT+1, formattedDate.length()-1);
    pDBGln(formattedDate);  
    pDBG("DATE: ");
    pDBGln(dayStamp);
    pDBG("HOUR: ");
    pDBGln(timeStamp);    
  #endif
  
  curDateTime  = formattedDate.substring(8,10);  //day
  curDateTime += formattedDate.substring(5,7);   //month
  curDateTime += formattedDate.substring(2,4);   //year
  curDateTime += formattedDate.substring(11,13); //hour
  curDateTime += formattedDate.substring(14,16); //minute
  curDateTime += formattedDate.substring(17,19); //seconds
  return curDateTime;
}

I want to run other routines but listen to any serial transfer when available. Technically I will use a GPIO to triggered from a PIR to wake the ESP32Cam from deep sleep then start the "mytransfer" function.

So in the loop section I want to call other routines / functions such as mqtt listeners or displays.

Added this into the loop above the CRC error checking and it works until I call my other functions

    if (packetCounter > 1) {
       //do nothing
    }
     else {
       check_Loop(); //call check loop
    }

Check_loop will hold other functions.

Issue I am struggling with is how to listen for a serial transfer but also run other routines. When a transfer is available stop the other routines to allow the transfer. When packetCounter is greater than 1 do nothing if less than one run the routines.

So the way I understand it is if(myTransfer.available()) then transfer the file, if not loop and wait, so how can I run other looping code and then stop if myTransfer.available is greater than 0 hence a transfer?

I need a way to see if there is a myTransfer.available() >0 for example but thats what myTransfer.available() does, what else can I look at to sense a transfer is available and if not loop other code?

Put the code that you want to run inside the code block for


if(myTransfer.available())

and put the code that you want to run otherwise in loop() outside of that code block

Is that what your current code does or do you have code in the dependant code block that should be in loop() ?

Use the FreeRTOS operating system that's already running inside all ESP32 processors to implement multi-tasking in the RX Master. You'd spin up one task to handle the SerialTransfer object and others to do the other functions.

Why not use freeROS the built in multitasking multi processing OS built into the ESP32?

#include "sdkconfig.h" // used for log printing
#include "esp_system.h"
#include "freertos/FreeRTOS.h" //freeRTOS items to be used
#include "freertos/task.h"
#include "certs.h"
#include "esp_camera.h"
#include "soc/soc.h"           // Disable brownout problems
#include "soc/rtc_cntl_reg.h"  // Disable brownout problems
#include "driver/rtc_io.h"
#include <WiFi.h>
#include <WiFiClient.h>
#include "ESP32_FTPClient.h"
//
WiFiClient wifiClient; // do the WiFi instantiation thing
ESP32_FTPClient ftp (ftp_server, ftp_user, ftp_pass, 5000, 2);
////
void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
{
  switch (event) {
    case SYSTEM_EVENT_STA_CONNECTED:
      log_i("Connected to WiFi access point");
      break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
      log_i("Disconnected from WiFi access point");
      break;
    case SYSTEM_EVENT_AP_STADISCONNECTED:
      log_i("WiFi client disconnected");
      break;
    default: break;
  }
} // void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
////
void setup()
{
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
  ////
  if ( configInitCamera() )
  {
    xTaskCreatePinnedToCore( capturePhoto_sendFTP, "capturePhoto_sendFTP", 20000, NULL, 3, NULL, 1 );
  } else {
    log_i( "camera failed to initilize. Quitting programed operations." );
  }
} // void setup()
////
void capturePhoto_sendFTP( void *pvParameters )
{
  TickType_t xLastWakeTime    = xTaskGetTickCount();
  const TickType_t xFrequency = 100; //delay for mS
  for (;;)
  {
    log_i( "tick");
    if ( WiFi.status() == WL_CONNECTED )
    {
      camera_fb_t * fb = NULL; // pointer
      fb = esp_camera_fb_get();
      if (!fb)
      {
        log_i( "Camera capture failed" );
      } else {
        ftp.OpenConnection(); // try open FTP
        if ( ftp.isConnected() )
        {
          //try send file ftp
          ftp.ChangeWorkDir( ftp_path );
          // Delete existing file, create the new file, and send the image to the file
          ftp.DeleteFile( ftp_file_name );
          ftp.InitFile( ftp_file_type ); //"Type I"
          ftp.NewFile( ftp_file_name );
          ftp.WriteData( (unsigned char *)fb->buf, fb->len );
          ftp.CloseFile();
          ftp.CloseConnection();
        }
        esp_camera_fb_return(fb); //return the frame buffer back to the driver for reuse
      }
    } else {
      log_i( "In capturePhoto_sendFTP found WiFi not connected ");
      connectToWiFi();
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete( NULL );
} //void capturePhoto_sendFTP( void *pvParameters )
////
void configureCameraSettings()
{
  sensor_t * s = esp_camera_sensor_get(); //see certs.h for more info
  s->set_brightness(s, -1);     // -2 to 2 **************************
  s->set_contrast(s, 0);       // -2 to 2
  s->set_saturation(s, 0);     // -2 to 2
  s->set_special_effect(s, 0); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
  s->set_whitebal(s, 1);       // 0 = disable , 1 = enable
  s->set_awb_gain(s, 1);       // 0 = disable , 1 = enable
  s->set_wb_mode(s, 0);        // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
  s->set_exposure_ctrl(s, 1);  // 0 = disable , 1 = enable
  s->set_aec2(s, 0);           // 0 = disable , 1 = enable
  s->set_ae_level(s, 0);       // -2 to 2
  s->set_aec_value(s, 300);    // 0 to 1200
  s->set_gain_ctrl(s, 1);      // 0 = disable , 1 = enable
  s->set_agc_gain(s, 0);       // 0 to 30
  s->set_gainceiling(s, (gainceiling_t)0);  // 0 to 6
  s->set_bpc(s, 0);            // 0 = disable , 1 = enable
  s->set_wpc(s, 1);            // 0 = disable , 1 = enable
  s->set_raw_gma(s, 1);        // 0 = disable , 1 = enable
  s->set_lenc(s, 1);           // 0 = disable , 1 = enable
  s->set_hmirror(s, 0);        // 0 = disable , 1 = enable
  s->set_vflip(s, 0);          // 0 = disable , 1 = enable
  s->set_dcw(s, 1);            // 0 = disable , 1 = enable
  s->set_colorbar(s, 0);       // 0 = disable , 1 = enable
} //void configureCameraSettings()
////
bool configInitCamera()
{
  camera_config_t config = {}; // Stores the camera configuration parameters
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer   = LEDC_TIMER_0;
  config.pin_d0       = GPIO_NUM_5; //Y2
  config.pin_d1       = GPIO_NUM_18; //Y3
  config.pin_d2       = GPIO_NUM_19; //Y4
  config.pin_d3       = GPIO_NUM_21; //Y5
  config.pin_d4       = GPIO_NUM_36; //Y6
  config.pin_d5       = GPIO_NUM_39; //Y7
  config.pin_d6       = GPIO_NUM_34; //Y8
  config.pin_d7       = GPIO_NUM_35; // Y9
  config.pin_xclk     = GPIO_NUM_0; //XCLK
  config.pin_pclk     = GPIO_NUM_22; //PCLK
  config.pin_vsync    = GPIO_NUM_25; //VSSYNC
  config.pin_href     = GPIO_NUM_23; // HREF
  config.pin_sscb_sda = GPIO_NUM_26; //SIOD
  config.pin_sscb_scl = GPIO_NUM_27; //SIOC
  config.pin_pwdn     = GPIO_NUM_32; //PWDN
  config.pin_reset    = -1; //RESET
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG; //assuming default is has PSRAM
  config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
  config.jpeg_quality = 10; //0-63 lower number means higher quality
  config.fb_count = 2;
  // Initialize the Camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    log_i("Camera init failed with error 0x%x", err);
    return false;
  } else {
    configureCameraSettings();
    return true;
  }
} //void configInitCamera()
////
void connectToWiFi()
{
  int TryCount = 0;
  while ( WiFi.status() != WL_CONNECTED )
  {
    TryCount++;
    WiFi.disconnect();
    WiFi.begin( SSID, PASSWORD );
    vTaskDelay( 4000 );
    if ( TryCount == 10 )
    {
      ESP.restart();
    }
  }
  WiFi.onEvent( WiFiEvent );
}
////
void loop() {}

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/freertos.html

Not sure that I follow you with "Put the code that you want to run inside the code block for"

if(myTransfer.available())

If myTransfer.available is greater than 0 then this means there is a serial transfer occurring.

So what I am trying to my head around is this as a example

void loop()
{ //start of the loop
  if (myTransfer.available())  {

    //if(packetCounter >= 1) {
    
    myTransfer.rxObj(ImgMetaData, sizeof(ImgMetaData));
    pDBG("Struct Data: ");
    pDBG(ImgMetaData.counter);
    pDBG(", ");
    pDBG(ImgMetaData.imSize);
    pDBG(", ");
    pDBG(ImgMetaData.numLoops);
    pDBG(", ");
    pDBG(ImgMetaData.sizeLastLoop);
    pDBG(", PacketCounter: ");
    pDBGln(packetCounter);

    if (ImgMetaData.counter == 1) {
      copyToImageBuff(MAX_PACKET_SIZE - sizeof(ImgMetaData));
    } else {
      if (ImgMetaData.counter == packetCounter) {
        if (packetCounter < ImgMetaData.numLoops) {
          copyToImageBuff(MAX_PACKET_SIZE - sizeof(ImgMetaData));
        } else if (ImgMetaData.counter == packetCounter) {
          copyToImageBuff(ImgMetaData.sizeLastLoop);
        }
      }
    }

    if (packetCounter > ImgMetaData.numLoops) {
      pic_name  = picPrefix;
      pic_name += getDateTime() + ".jpg";
      //FTP_upload();
      pDBGln("FTP Upload"); //added
      packetCounter = 1;
      bufferPointer = 0;
      delay(2000);
      //while(1){}
    }


  } else if (myTransfer.status < 0) {
    pDBG("ERROR: ");
    if (myTransfer.status == -1)
      pDBGln(F("CRC_ERROR"));
    else if (myTransfer.status == -2)
      pDBGln(F("PAYLOAD_ERROR"));
    else if (myTransfer.status == -3)
      pDBGln(F("STOP_BYTE_ERROR"));
  }

    if (packetCounter > 1) {
    //do nothing
    } else  {
     Update_temp();
   } 

} 

Outside of the loop but called is by

if (myTransfer.available())  {
void copyToImageBuff(uint16_t dataLenght) {
  for (int y = 0; y < dataLenght; y++) {
    tempImageBuffer[bufferPointer + y] = myTransfer.rxBuff[y + sizeof(ImgMetaData)];
  }
  bufferPointer += dataLenght;
  packetCounter++;

  pDBG("dataLenght: ");
  pDBG(dataLenght);
  pDBG(", bufferPointer: ");
  pDBGln(bufferPointer);
}

void printBuf(char localBuff) {
  pDBG(F("Pixel Values: { "));
  for (uint16_t k = 0; k < sizeof(myTransfer.rxBuff); k++) {
    pDBG(myTransfer.rxBuff[k]);
    if (k < (sizeof(myTransfer.rxBuff) - 1))
      pDBG(F(", "));
    else
      pDBGln(F(" }"));
  }
}

void FTP_upload() {
  pDBG("Uploading via FTP: ");
  ftp.OpenConnection();
  ftp.ChangeWorkDir("/domain.com/Camera");
  //Create a file and write the image data to it;
  ftp.InitFile("Type I");
  const char *f_name = pic_name.c_str();
  ftp.NewFile( f_name );
  pDBGln( f_name );
  ftp.WriteData((unsigned char*)tempImageBuffer, ImgMetaData.imSize);
  ftp.CloseFile();
  // Breath, withouth delay URL failed to update.
  pDBGln("Done... Waiting next transfer...");
  delay(100);
}

String getDateTime() {
  String curDateTime = "";

  while (!timeClient.update()) {
    timeClient.forceUpdate();
  }
  // The formattedDate comes with the following format:
  // 2018-05-28T16:00:13Z
  // We need to extract date and time
  formattedDate = timeClient.getFormattedDate();

#ifdef DEGUB_ESP
  // Extract date
  int splitT = formattedDate.indexOf("T");
  dayStamp = formattedDate.substring(0, splitT);
  // Extract time
  timeStamp = formattedDate.substring(splitT + 1, formattedDate.length() - 1);
  pDBGln(formattedDate);
  pDBG("DATE: ");
  pDBGln(dayStamp);
  pDBG("HOUR: ");
  pDBGln(timeStamp);
#endif

  curDateTime  = formattedDate.substring(8, 10); //day
  curDateTime += formattedDate.substring(5, 7);  //month
  curDateTime += formattedDate.substring(2, 4);  //year
  curDateTime += formattedDate.substring(11, 13); //hour
  curDateTime += formattedDate.substring(14, 16); //minute
  curDateTime += formattedDate.substring(17, 19); //seconds
  return curDateTime;
}
void Update_temp() // update temp if connection
{
  TempCount++; // increment x by one and returns the old value of x
  //Serial.println(TempCount);
  if (TempCount >= 14400) { // check every 4hrs
    TempCount = 0;
    //temp = modem.getTemperature(); //get CPUtem
    Serial.print("Temperature: ");
    Serial.println(temp);
    temp = modem.getTemperature(); //get CPUtem
    // Convert the value to a char array
    char tempString[8];
    dtostrf(temp, 1, 2, tempString);
    mqtt.publish(topicTemperature, tempString);
  }
}

So being very simplistic if the packetCounter is greater than 1 a serial transfer is occurring, if less than 1 run the other code in the loop such as Update_temp()

    if (packetCounter > 1) {
    //do nothing
    } else  {
     Update_temp();
   } 

This semi works but induces a CRC error. If I replace with this it prints here looping and then when a serial transfer comes in it stops and serial2 - myTransfer.available starts and finishes

    if (packetCounter > 1) {
    //do nothing
    } else  {
    // Update_temp();
  pDBG("here looping ")
   } 

In my limited understanding I just need to determine if there is a serial transfer available else run the rest of the loop code.

I have been looking to see if there is another state to look at to determine

if (myTransfer.available())  {

or 
myTransfer.status == 0

or 

packetCounter > 1

or a mix of a few together. Literally spent hours due to my lack of understanding.

Many thanks and yes this would be good but will take me some time to get my head around this.

Output to the serial monitor below shows that the PacketCounter is not increasing

image

Which to me is the simple is not working as I expect? Remark out // Update_temp(); and the output via the serial transfer is as expected

image

if (packetCounter > 1) {
void copyToImageBuff(uint16_t dataLenght) {
  for (int y = 0; y < dataLenght; y++) {
    tempImageBuffer[bufferPointer + y] = myTransfer.rxBuff[y + sizeof(ImgMetaData)];
  }
  bufferPointer += dataLenght;
  packetCounter++;

What I was trying to describe was a code structure like this

void loop()
{
  if(myTransfer.available())
  {
    //code here to deal with available data
  }
//unconditional code here
}

Like this correct?

void loop()
{ 
  if (myTransfer.available())
  {
    myTransfer.rxObj(ImgMetaData, sizeof(ImgMetaData));
    pDBG("Struct Data: ");
    pDBG(ImgMetaData.counter);
    pDBG(", ");
    pDBG(ImgMetaData.imSize);
    pDBG(", ");
    pDBG(ImgMetaData.numLoops);
    pDBG(", ");
    pDBG(ImgMetaData.sizeLastLoop);
    pDBG(", PacketCounter: ");
    pDBGln(packetCounter);

    if (ImgMetaData.counter == 1) {
      copyToImageBuff(MAX_PACKET_SIZE - sizeof(ImgMetaData));
    } else {
      if (ImgMetaData.counter == packetCounter) {
        if (packetCounter < ImgMetaData.numLoops) {
          copyToImageBuff(MAX_PACKET_SIZE - sizeof(ImgMetaData));
        } else if (ImgMetaData.counter == packetCounter) {
          copyToImageBuff(ImgMetaData.sizeLastLoop);
        }
      }
    }

    if (packetCounter > ImgMetaData.numLoops) {
      pic_name  = picPrefix;
      pic_name += getDateTime() + ".jpg";
      //FTP_upload();
      pDBGln("FTP Upload"); //added
      packetCounter = 1;
      bufferPointer = 0;
      delay(2000);
      //while(1){}
    }

  } else if (myTransfer.status < 0) {
    pDBG("ERROR: ");
    if (myTransfer.status == -1)
      pDBGln(F("CRC_ERROR"));
    else if (myTransfer.status == -2)
      pDBGln(F("PAYLOAD_ERROR"));
    else if (myTransfer.status == -3)
      pDBGln(F("STOP_BYTE_ERROR"));
  }

    //check_Loop();
    //Check_PIR();
    Update_temp();

} // close of loop section

Result

Maybe. It depends on what code you want to run unconditionally. In the code that you posted the only unconditional code in loop() is the call to Update_temp()

I need to run connections to monitor Mqtt, temp, shake sensors and check if network connected. I did try and do similar to you last example but with a else as well to call other code blocks if not transfer available. Also update a LCD display with its current state. Trying to get the bare minimal code going then add to it. Really just need to run other looping code blocks and stop only when a serial transfer available.

What happened when you tried the suggested structure ?

The code in loop() or called from it should run unconditionally but must not contain blocking code otherwise you will miss the fact that serial data is available()

For Update_temp();

Getting the following where the PacketCounter doesnt increase and that generates a CRC error.

ERROR: CRC_ERROR
Struct Data: 85, 25943, 106, 113, PacketCounter: 1
ERROR: CRC_ERROR
Struct Data: 88, 25943, 106, 113, PacketCounter: 1
Struct Data: 89, 25943, 106, 113, PacketCounter: 1
ERROR: CRC_ERROR
Struct Data: 92, 25943, 106, 113, PacketCounter: 1
ERROR: CRC_ERROR

Have another example loop block Check_PIR()

void Check_PIR()
{
  // PIR Detector
  int pirState = digitalRead(pirPin);
  if (pirState)   // if LOW to HIGH
  {
    Short_Flash_LED();
    temp = modem.getTemperature(); //get CPUtem
    //Serial.print("Status: ");
    //Serial.println("Motion Detected!");
    //Serial.print("Trigger Count: ");
    //Serial.println(TriggerCount);
    PIR_Triggered(); //Call Trigger Function
  }
}

which calls

void PIR_Triggered()
{
  TriggerTimes[TriggerCount++] = millis();
  if (TriggerCount >= 5)
  {
    // SOUND THE ALARM HERE
    TriggerCount = 0;
    countDown = 0;
    //Serial.print("Status: ");
    //Serial.println("Alarm triggered, alert sent!");
    //Serial.print("Trigger, 5x threshold met, reset trigger to: ");
    //Serial.println(TriggerCount);
    //Serial.print("Trigger, 50s threshold met, reset counter to: ");
    //Serial.println(countDown);
    mqtt.publish(topicPIRAlarm, "Movement Triggered!");
    Movement_NoMovement(); //display alarms
    Long_Flash_LED ();
    mqtt.publish(topicPIRAlarm, "Alarm Clear"); // Tell Home Assistance
  }
}

result on first run

Struct Data: 108, 26827, 110, 13, PacketCounter: 108
dataLenght: 246, bufferPointer: 26568
Struct Data: 109, 26827, 110, 13, PacketCounter: 109
dataLenght: 246, bufferPointer: 26814
Struct Data: 110, 26827, 110, 13, PacketCounter: 110
dataLenght: 13, bufferPointer: 26827
FTP Upload

Second run

Struct Data: 106, 27001, 110, 187, PacketCounter: 106
dataLenght: 246, bufferPointer: 26076
Struct Data: 107, 27001, 110, 187, PacketCounter: 107
dataLenght: 246, bufferPointer: 26322
Struct Data: 108, 27001, 110, 187, PacketCounter: 108
dataLenght: 246, bufferPointer: 26568
Struct Data: 109, 27001, 110, 187, PacketCounter: 109
dataLenght: 246, bufferPointer: 26814
Struct Data: 110, 27001, 110, 187, PacketCounter: 110
dataLenght: 187, bufferPointer: 27001
FTP Upload

Now trigger PIR

and send a serial transfer

image

I guess its running the loop trigger PIR and then looping and gets the serial transfer which causes the last CRC error and stops PacketCounter increasing.

Ideal would be to have blocks of code looping then when the PIR is triggered wake the ESP32CAM via GPIO and then listen this way the above condition doesnt occur?

Start with something very simple like blinking an LED or printing a value at intervals in loop() using millis() timing and printing what you receive when serial data is available

Once that is working you can add more unconditional code in loop()

Thanks and yes. Started with printing to the serial console (like Serial.println("here!"); and will continue, note adding a delay delay(1000); to slow it down to view and troubleshoot. The delay incurrs a CRC, reduce the delay to say 100 and its fine. So I understand this is part of the loop.

Question that I dont understand. myTransfer.available() is serial2, and coded to go to two GPIO pins. When the serial transfer occurs isnt this transferring the data serially to these to Pins (tx/rx)? So in my mind I should be able to completed a transfer but also send data to the serial console?

Example of temp updating every 1second with the serial transfer, transferring data. Temp is writting to serial console and myTransfer.available and myTransfer.rxObj(ImgMetaData, sizeof(ImgMetaData)); to the different allocated pins. So what is wrong with my understanding? Is it the fact that the serial transfer has to complete before sending any other serial print? Sorry if this is a stupid question.

image

Ok finally getting further..... hoping for some more guidance.

ESP32CAM - Slave is running of the ESP32 Master. After powering on both (Master/Slave) I ask the ESP32CAM Slave to go to sleep.

Place the Master RX looping code in to a separate function this way the other code can loop.
If a serial transfer is available the loop stops, reads the transfer then starts the loop and run the other code. This appears to work as expected except on the initial boot of both Master/Slave.

Master Loop code - So now call check_camera(); to check if the ESP32CAM is sending a jpg
check_camera() calls the Master RX code from thread above...

if PIR triggers 5 times it will set pirCAMState to HIGH.

void loop()
{ //start of the loop

check_camera();
  if(pirCAMState == HIGH)  {
     check_camera();
  }
  else {
       pirCAMState = LOW; 

Slave ESP32CAM Code

#define DEBUG_ESP              //comment out to deactivate debug console

#ifdef DEBUG_ESP
  #define pDBGln(x) Serial.println(x)
  #define pDBG(x)   Serial.print(x)
#else 
  #define pDBG(...)
  #define pDBGln(...)
#endif

#include "esp_camera.h"
#include "Arduino.h"
#include "soc/soc.h"           // Disable brownour problems
#include "soc/rtc_cntl_reg.h"  // Disable brownour problems
#include "driver/rtc_io.h"
#include "SerialTransfer.h"

// Pin definition for CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

#define GPIO_PIN_WAKEUP GPIO_NUM_12 //Wake up from Deep Sleep

SerialTransfer myTransfer;
HardwareSerial Comm(1);
struct img_meta_data{
  uint16_t counter;
  uint16_t imSize;
  uint16_t numLoops;
  uint16_t sizeLastLoop;
} ImgMetaData;
const uint16_t PIXELS_PER_PACKET = MAX_PACKET_SIZE - sizeof(ImgMetaData);

void setup(){
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
 
  Serial.begin(115200);                     // Define and start serial monitor
  // 115200,256000,512000,962100
  Comm.begin(962100, SERIAL_8N1,15,14);     //, Comm_Rxd_pin, Comm_Txd_pin); // Define and start Comm serial port
  myTransfer.begin(Comm);
 
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
 
  config.frame_size = FRAMESIZE_SVGA;
  config.jpeg_quality = 12;
  config.fb_count = 1;
 
  // Init Camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK){
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  // Turns off the ESP32-CAM white on-board LED (flash) connected to GPIO 4
  pinMode(4, OUTPUT); //Flashes the on-board LED
  digitalWrite(4, HIGH);
  delay(100); //Flash on-board LED
  digitalWrite(4, LOW);
  delay(100); //Flash on-board LED
  digitalWrite(4, HIGH);

  uint16_t startIndex = 0;
  camera_fb_t * fb = NULL;
  //Take Picture with Camera
  fb = esp_camera_fb_get(); 
  
  delay(200); //leave LED on for 500ms
  digitalWrite(4, LOW); //turn LED off
  rtc_gpio_hold_en(GPIO_NUM_4); //deep sleep mode to prevent the pin configuration from changing

  ImgMetaData.imSize       = fb->len;                             //sizeof(myFb);
  ImgMetaData.numLoops     = (fb->len / PIXELS_PER_PACKET) + 1;   //(sizeof(myFb)/PIXELS_PER_PACKET) + 1; 
  ImgMetaData.sizeLastLoop = fb->len % PIXELS_PER_PACKET;         //(sizeof(myFb)%PIXELS_PER_PACKET);

  for(ImgMetaData.counter=1; ImgMetaData.counter<=ImgMetaData.numLoops; ImgMetaData.counter++){
    myTransfer.txObj(ImgMetaData, sizeof(ImgMetaData));
    //printStructBuf();
    stuffPixels(fb->buf, startIndex, sizeof(ImgMetaData), PIXELS_PER_PACKET);
    //stuffPixels(myFb, startIndex, sizeof(ImgMetaData), PIXELS_PER_PACKET);
    //printStructBuf();   
    myTransfer.sendData(MAX_PACKET_SIZE);
     
    pDBGln(F("Sent:"));
    pDBG(F("img.counter: "));      pDBGln((uint16_t)((myTransfer.txBuff[1] << 8) | myTransfer.txBuff[0]));
    pDBG(F("img.imSize: "));       pDBGln((uint16_t)((myTransfer.txBuff[3] << 8) | myTransfer.txBuff[2]));
    pDBG(F("img.numLoops: "));     pDBGln((uint16_t)((myTransfer.txBuff[5] << 8) | myTransfer.txBuff[4]));
    pDBG(F("img.sizeLastLoop: ")); pDBGln((uint16_t)((myTransfer.txBuff[7] << 8) | myTransfer.txBuff[6]));

    startIndex += PIXELS_PER_PACKET;    
    delay(100);
    //printBuf();  
  }
  esp_camera_fb_return(fb);   //clear camera memory
  
  delay(1000);
  // Onboard RED LED
  pinMode(33, OUTPUT);
  digitalWrite(33, LOW);
  pinMode(GPIO_PIN_WAKEUP, INPUT);
}

void loop(){
  int wakeupPinState=digitalRead(GPIO_PIN_WAKEUP);
  if(wakeupPinState==HIGH){
  } else {
      gotoSleep();
    }
  }


void printStructBuf(){
  pDBG(F("Internal Struct: { "));
  for (uint16_t k=0; k<sizeof(ImgMetaData); k++){
    pDBG(myTransfer.txBuff[k]);
    if (k<(sizeof(ImgMetaData)-1))
      pDBG(F(", "));
    else
      pDBGln(F(" }"));
  }
}

void printBuf(){
  pDBG(F("Pixel Values: { "));
  for (uint16_t k=8; k<MAX_PACKET_SIZE; k++){
    pDBG(myTransfer.txBuff[k]);
    if (k < (MAX_PACKET_SIZE - 1))
      pDBG(F(", "));
    else
      pDBGln(F(" }"));
  }
  pDBGln();
}

void stuffPixels(const uint8_t * pixelBuff, const uint16_t &bufStartIndex, const uint16_t &txStartIndex, const uint16_t &len){
  uint16_t txi = txStartIndex;
  for (uint16_t i=bufStartIndex; i<(bufStartIndex + len); i++)  {
    myTransfer.txBuff[txi] = pixelBuff[i];
    txi++;
  }
}


void gotoSleep(){
  Serial.println("Going to sleep now...");
  esp_sleep_enable_ext0_wakeup(GPIO_PIN_WAKEUP, HIGH);
  esp_deep_sleep_start();
}

Issue is this seems to be a state that causes the Master to think there is a CRC error.
Reset the ESP32CAM slave and it will serially transfer JPEG to the Master with out issue.
From the original Slave sender code I have added lines below (Slave ESP PIN 12 appears to support deep sleep RTC).

#define GPIO_PIN_WAKEUP GPIO_NUM_12 //Wake up from Deep Sleep

void setup(){
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector

  pinMode(GPIO_PIN_WAKEUP, INPUT);
}

void loop(){
  int wakeupPinState=digitalRead(GPIO_PIN_WAKEUP);
  if(wakeupPinState==HIGH){
  } else {
      gotoSleep();
    }
  }

void gotoSleep(){
  Serial.println("Going to sleep now...");
  esp_sleep_enable_ext0_wakeup(GPIO_PIN_WAKEUP, HIGH);
  esp_deep_sleep_start();
}

From the master I call when PIR trigger if triggered 5x sets pirCAMState to ...

pirCAMState = HIGH;

then Slave loop looks for pirCAMState is HIGH and if so runs the digitalWrite against PIN 12

//ESP32CAM Wake
delay(1000);
digitalWrite(pirCAM, HIGH); //HIGH
delay(500);

Master code that calls the ESP32CAM Slave from Deep Sleep

//PIR ESP32CAM
int pirCAM = 5;         // PIR Out pin
int pirCAMState = LOW;  // PIR status 

//ESP32CAM
pinMode(pirCAM, OUTPUT);
digitalWrite(pirCAM, LOW);

void Setup()
 digitalWrite(pirCAM, LOW); // Reset the cam from boot and put to sleep // added 11/10/2022
 Serial.println(pirCAMState);
}

void PIR_Triggered()
{
  TriggerTimes[TriggerCount++] = millis();
  if (TriggerCount >= 5)
  {
    // SOUND THE ALARM HERE
    TriggerCount = 0;
    countDown = 0;
    pirCAMState = HIGH;

    mqtt.publish(topicPIRAlarm, "Movement Triggered!");

    Movement_NoMovement(); //display alarms om LCD
    Long_Flash_LED (); // Flash ESP32CAM Onboard LED
    mqtt.publish(topicPIRAlarm, "Alarm Clear"); // Pub to MQTT

    //ESP32CAM Wake
    delay(1000); // 
    digitalWrite(pirCAM, HIGH); //HIGH
    delay(500); //Let the ESP32CAM boot

  }
}

So my question is why from boot does the ESP32CAM Slave appears to enter a mode where it needs a reset?

If I boot the ESP32CAM by itself code appears to execute as expected (thats not powered of the Master)

Compared the outputs of initial boot then triggered the PIR to take and send via serial a jpg
And then reset the ESP32CAM Slave and triggered the PIR to take and send via serial a jpg

Outputs below you see the initial boot of Master/Slave is a CRC
Reset Master/Slave same code and no CRC its works as expected.

Initial boot for Master and Slave (slave is powered off the master) PacketCounter stays at 1

Message arrived [test/PIRonoff]: ON
**ERROR: CRC_ERROR**
Struct Data: 2, 24755, 101, 155, PacketCounter: 1
Struct Data: 3, 24755, 101, 155, PacketCounter: 1
Struct Data: 4, 24755, 101, 155, PacketCounter: 1
Struct Data: 5, 24755, 101, 155, PacketCounter: 1

Reset Master, reset Slave. PacketCounter adds to complete

Message arrived [test/PIRonoff]: ON
PIRonoffStatus:1
Struct Data: 1, 25690, 105, 106, PacketCounter: 1
dataLenght: 246, bufferPointer: 246
Struct Data: 2, 25690, 105, 106, PacketCounter: 2
dataLenght: 246, bufferPointer: 492
Struct Data: 3, 25690, 105, 106, PacketCounter: 3

How do I now troubleshoot?
GPIO Deep Sleep PIN 12 on the Slave ESP32CAM support RTC
Direct connection between Master to Slave no pull up or down resistors
Powering the ESPCAM32 off Master on 3.3v see some reports of issues but after the reset it works as expected.

Took me a while but figured it out in the end. CRC was caused but the Slave code looping. Added a delay as I couldnt work out how to make the slave stop after a single loop as below. In the end added a delay for 10s before telling the GPIO pin to go low hence go to deep sleep. Seems to work the way I need it to.

if((wakeupPinState == HIGH) && (countloop < 1)) { //if the loop count is less than 2 run if not go to sleep
#define DEBUG_ESP              //comment out to deactivate debug console

#ifdef DEBUG_ESP
  #define pDBGln(x) Serial.println(x)
  #define pDBG(x)   Serial.print(x)
#else 
  #define pDBG(...)
  #define pDBGln(...)
#endif

#include "esp_camera.h"
#include "Arduino.h"
#include "soc/soc.h"           // Disable brownour problems
#include "soc/rtc_cntl_reg.h"  // Disable brownour problems
#include "driver/rtc_io.h"
#include "SerialTransfer.h"

// Pin definition for CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

#define GPIO_PIN_WAKEUP GPIO_NUM_12 //Bootstrap Wake up from Deep Sleep  //https://github.com/raphaelbs/esp32-cam-ai-thinker/blob/master/docs/esp32cam-pin-notes.md#gpio12---hs2_data2
//#define GPIO_PIN_WAKEUP GPIO_NUM_13 // https://randomnerdtutorials.com/esp32-cam-pir-motion-detector-photo-capture/

//ESP32CAM Wakeup set low on boot 
int wakeupPinState = LOW;         

SerialTransfer myTransfer;
HardwareSerial Comm(1);
struct img_meta_data{
  uint16_t counter;
  uint16_t imSize;
  uint16_t numLoops;
  uint16_t sizeLastLoop;
} ImgMetaData;
const uint16_t PIXELS_PER_PACKET = MAX_PACKET_SIZE - sizeof(ImgMetaData);

void setup(){
  //delay(90000); //added to delay start up to allow master to get ready 
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
 
  Serial.begin(115200);                     // Define and start serial monitor
  // 115200,256000,512000,962100
  Comm.begin(962100, SERIAL_8N1,15,14);     //, Comm_Rxd_pin, Comm_Txd_pin); // Define and start Comm serial port
  myTransfer.begin(Comm);
 
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
 
  config.frame_size = FRAMESIZE_SVGA;
  config.jpeg_quality = 12;
  config.fb_count = 1;
 
  // Init Camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK){
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  // setup wake pin
  pinMode(GPIO_PIN_WAKEUP, INPUT);
}

void loop(){
  int wakeupPinState=digitalRead(GPIO_PIN_WAKEUP);
  if(wakeupPinState==HIGH) {
  Serial.print("Camera waking Up: ");

  // Turns off the ESP32-CAM white on-board LED (flash) connected to GPIO 4
  pinMode(4, OUTPUT); //Flashes the on-board LED
  digitalWrite(4, HIGH);
  delay(100); //Flash on-board LED
  digitalWrite(4, LOW);
  delay(100); //Flash on-board LED
  digitalWrite(4, HIGH);
  delay(100); //Flash on-board LED
  digitalWrite(4, LOW);
  rtc_gpio_hold_en(GPIO_NUM_4); //deep sleep mode to prevent the pin configuration from changing


  uint16_t startIndex = 0;
  camera_fb_t * fb = NULL;
  //Take Picture with Camera
  fb = esp_camera_fb_get(); 

  ImgMetaData.imSize       = fb->len;                             //sizeof(myFb);
  ImgMetaData.numLoops     = (fb->len / PIXELS_PER_PACKET) + 1;   //(sizeof(myFb)/PIXELS_PER_PACKET) + 1; 
  ImgMetaData.sizeLastLoop = fb->len % PIXELS_PER_PACKET;         //(sizeof(myFb)%PIXELS_PER_PACKET);

  for(ImgMetaData.counter=1; ImgMetaData.counter<=ImgMetaData.numLoops; ImgMetaData.counter++){
    myTransfer.txObj(ImgMetaData, sizeof(ImgMetaData));
    //printStructBuf();
    stuffPixels(fb->buf, startIndex, sizeof(ImgMetaData), PIXELS_PER_PACKET);
    //stuffPixels(myFb, startIndex, sizeof(ImgMetaData), PIXELS_PER_PACKET);
    //printStructBuf();   
    myTransfer.sendData(MAX_PACKET_SIZE);
     
    pDBGln(F("Sent:"));
    pDBG(F("img.counter: "));      pDBGln((uint16_t)((myTransfer.txBuff[1] << 8) | myTransfer.txBuff[0]));
    pDBG(F("img.imSize: "));       pDBGln((uint16_t)((myTransfer.txBuff[3] << 8) | myTransfer.txBuff[2]));
    pDBG(F("img.numLoops: "));     pDBGln((uint16_t)((myTransfer.txBuff[5] << 8) | myTransfer.txBuff[4]));
    pDBG(F("img.sizeLastLoop: ")); pDBGln((uint16_t)((myTransfer.txBuff[7] << 8) | myTransfer.txBuff[6]));

    startIndex += PIXELS_PER_PACKET;    
    delay(100);
    //printBuf();  
  }
  esp_camera_fb_return(fb);   //clear camera memory

  // Onboard RED LED
  pinMode(33, OUTPUT);
  digitalWrite(33, LOW);
  Serial.println("Waiting 10s for serial transfer to finish...");
  delay(10000); // allow for a single transfer then go to sleep
    
  } else {
    gotoSleep();
    }
    
} //end of loop

void printStructBuf(){
  pDBG(F("Internal Struct: { "));
  for (uint16_t k=0; k<sizeof(ImgMetaData); k++){
    pDBG(myTransfer.txBuff[k]);
    if (k<(sizeof(ImgMetaData)-1))
      pDBG(F(", "));
    else
      pDBGln(F(" }"));
  }
}

void printBuf(){
  pDBG(F("Pixel Values: { "));
  for (uint16_t k=8; k<MAX_PACKET_SIZE; k++){
    pDBG(myTransfer.txBuff[k]);
    if (k < (MAX_PACKET_SIZE - 1))
      pDBG(F(", "));
    else
      pDBGln(F(" }"));
  }
  pDBGln();
}

void stuffPixels(const uint8_t * pixelBuff, const uint16_t &bufStartIndex, const uint16_t &txStartIndex, const uint16_t &len){
  uint16_t txi = txStartIndex;
  for (uint16_t i=bufStartIndex; i<(bufStartIndex + len); i++)  {
    myTransfer.txBuff[txi] = pixelBuff[i];
    txi++;
  }
}

void gotoSleep(){
  Serial.print("Going to sleep now...");
  esp_sleep_enable_ext0_wakeup(GPIO_PIN_WAKEUP, HIGH);
  esp_deep_sleep_start();
}

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