Been working on a project for some time and hit a roadblock.
ESP32Cam32 serially sends to the Master and then Master uploads images via wireless to FTP site.
Original code uploads image to FTP via wireless, I wont have wireless and need to do via 4/5G to FTP site
Tx ESP32Cam (Slave)
#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[] = "x.x.x.x";
char ftp_user[] = "user";
char ftp_pass[] = "pass";
// 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;
}
Slave (ESP32Cam) serially sends its photo to the Master ESP32
Original coder used FTP library in my case I wont have wifi at the location and have the SIM 4/5G hence here is the issue to solve.
I need to convert this code block to use 4/5G rather than wifi/FTP.
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); //void WriteData (unsigned char * data, int dataLength);
ftp.CloseFile();
// Breath, withouth delay URL failed to update.
pDBGln("Done... Waiting next transfer...");
delay(100);
}
My 4/5G GPRS FTP Upload Code Block
void FTP4G_upload() {
String res;
Serial.println("Uploading via FTP: ");
//FTP Start
modem.sendAT("+CFTPSSTART"); //used to start FTP
modem.waitResponse(1000L);
pDBG(res);
if (modem.waitResponse(10000L) != 0) { //x is not equal to y
pDBGln("+CFTPSSTART failed to start");
delay(500);
pDBGln("+CFTPSSTART retrying...");
modem.sendAT("+CFTPSSTART"); //try again
modem.waitResponse(10000L);
pDBG(res);
return;
}
else {
(modem.waitResponse() == 0);
pDBG(res);
pDBGln("+CFTPSSTART started");
}
//FTP Login
modem.sendAT("+CFTPSLOGIN=\"", ftp_serverIP, ("\","), 21,(",\""), ftp_user,("\",\""), ftp_pass,("\","),0);
if (modem.waitResponse(2000L) != 1) {
pDBGln("+CFTPSLOGIN Fail");
}
//modem.waitResponse(4000L, res);
//pDBG(res);
//Set FTP Type to binary
modem.sendAT("+CFTPTYPE=", ftp_type);
modem.waitResponse(1000L, res);
pDBG(res);
if (modem.waitResponse(10000L) != 0) {
pDBGln("+CFTPSTYPE Fail");
}
//Change Directory
//modem.sendAT("+CFTPSCWD\"", ftp_pwd,("\"")); //e.g. AT+CFTPSCWD=”/lu.liu/TEST7600”
modem.sendAT("+CFTPSCWD=\"", ftp_pwd,("\"")); //e.g. AT+CFTPSCWD /domain.com/Camera
modem.waitResponse(1000L, res);
pDBG(res);
if (modem.waitResponse(10000L) != 0) {
pDBGln("+CFTPSLIST Fail");
}
//List Files
modem.sendAT("+CFTPSLIST=\"", ftp_list,("\"")); //AT+CFTPSLIST=”/”
modem.waitResponse(1000L, res);
pDBG(res);
if (modem.waitResponse(10000L) != 0) {
pDBGln("+CFTPSLIST Fail");
}
//Write File
const char *f_name = pic_name.c_str();
//ftp.NewFile( f_name );
pDBGln( f_name );
//ftp.WriteData((unsigned char*)tempImageBuffer, ImgMetaData.imSize);
char ftp_data = ((unsigned char*)tempImageBuffer, ImgMetaData.imSize); //e.,g AT+CFTPSPUT=”<filepath>”[,<data_len>[,<rest_size>]]
//modem.sendAT("+CFTPSPUT=\"", ftp_data,("\"")); //e.g. AT+CFTPSPUT=”/LK/LM/LO.TXT”
//modem.sendAT("+CFTPSPUT=\"", ftp_pwd,("/"), f_name, ftp_data,("\""));
//modem.sendAT("+CFTPSPUT=\"", ftp_pwd,("/"), f_name, ("\""));
// pDBG(res);
//if (modem.waitResponse(10000L) != 0) {
// pDBGln("+CFTPSPUT Fail");
//}
//modem.sendAT("+CFTPSPUTFILE=\"", ftp_pwd,("/"), f_name,("\","),1); //e.g. AT+CFTPSPUT=”/LK/LM/LO.TXT” correct but there is no file to FTP
//Logout of the FTP server
modem.sendAT("+CFTPSLOGOUT"); //used to stop FTP AT+CFTPSLOGOUT
modem.waitResponse(10000L);
pDBG(res);
if (modem.waitResponse(1000L) != 0) { //x is not equal to y
pDBGln("+CFTPSLOGOUT Failed to logout");
delay(500);
pDBGln("+CFTPSLOGOUT retrying...");
modem.sendAT("+CFTPSLOGOUT"); //try again
modem.waitResponse(10000L);
pDBG(res);
return;
}
else {
(modem.waitResponse() == 0);
pDBG(res);
pDBGln("+CFTPSLOGOUT logged out successfully");
}
//Stop the FTP service
modem.sendAT("+CFTPSSTOP"); //Check if the FTP service is running
modem.waitResponse(1000L);
pDBG(res);
if (modem.waitResponse() != 0) {
pDBG(res);
pDBGln("+CFTPSSTOP failed to stop ");
modem.sendAT("+CFTPSSTOP");
modem.waitResponse(10000L);
pDBG(res);
return;
}
else {
(modem.waitResponse() == 0);
pDBG(res);
pDBGln("+CFTPSSTOP service stopped successfully");
}
}
I have most of the code sorted output below shows it logging and if needed create a blank jpg.
17:11:29.534 -> Struct Data: 103, 25422, 104, 84, PacketCounter: 103
17:11:29.581 -> dataLenght: 246, bufferPointer: 25338
17:11:29.675 -> Struct Data: 104, 25422, 104, 84, PacketCounter: 104
17:11:29.675 -> dataLenght: 84, bufferPointer: 25422
17:11:29.675 -> FTP Upload
17:11:29.675 -> Uploading via FTP:
17:11:29.675 -> AT+CFTPSSTART
17:11:29.722 -> +CFTPSSTART: 0
17:11:29.722 -> OK
17:11:40.727 -> +CFTPSSTART started
17:11:40.727 -> AT+CFTPSLOGIN="x.x.x.x",21,"FTPuser","xxxxx",0
17:11:40.727 -> OK
17:11:40.727 -> AT+CFTPTYPE=I
17:11:40.727 -> OK
17:11:44.515 -> +CFTPSLOGIN: 0
17:11:50.744 -> AT+CFTPSCWD="/domain.com/Camera"
17:11:50.744 -> OK
17:11:51.026 -> +CFTPSCWD: 0
17:12:00.747 -> AT+CFTPSLIST="/domain.com/Camera"
17:12:00.794 -> OK
17:12:01.496 -> +CFTPSLIST: DATA,672
17:12:01.544 -> -rw-r--r-- 1 FTPuser pg1263480 21703 Oct 3 00:10 test.jpg
17:12:01.730 -> +CFTPSLIST: 0
17:12:10.781 -> 091122161129.jpg
17:12:10.781 -> AT+CFTPSLOGOUT
17:12:10.781 -> OK
17:12:10.828 -> +CFTPSLOGOUT: 0
17:12:12.789 -> OK
17:12:12.789 -> +CFTPSLOGOUT logged out successfully
17:12:12.789 -> AT+CFTPSSTOP
17:12:12.789 -> +CFTPSSTOP: 0
17:12:14.794 -> OK
17:12:14.794 -> +CFTPSSTOP service stopped successfully
17:12:18.808 -> AT+CGREG?
17:12:18.808 -> +CGREG: 0,1
17:12:18.808 -> OK
17:12:18.808 -> AT+CIPRXGET=4,0
17:12:18.808 -> +CIPRXGET: 4,0,80
17:12:18.808 -> OK
17:12:18.808 -> AT+CIPSEND=0,2
17:12:18.853 ->
The part I dont know how to tackle or even how to start is the that the original code uses wireless/FTP and I need to use 4/5G GPRS and FTP.
Only library I can find is TinyGSM which does eventhing except the FTP side. SIM board supports AT commands and FTPS so again thats all working.
I need some guidance on how to create the file and send the image data to ftp over GPRS 4/5G. I have tried to work out each step above and now need some guidance on how to
take the ftp.WriteData((unsigned char*)tempImageBuffer, ImgMetaData.imSize); and do the same step over GPRS 4/5G / ftp.
Any guidance here, tried searching but not getting far to how I even start this.
const char *f_name = pic_name.c_str();
ftp.NewFile( f_name );
ftp.WriteData((unsigned char*)tempImageBuffer, ImgMetaData.imSize); //void WriteData (unsigned char * data, int dataLength);
ftp.CloseFile();