How to combined code and make it work

I'm trying to join this 2 codes but the one from the web server doesn't work, it for ESP32

//web server
#include <Arduino.h>
#include <FS.h>
#include <SPIFFS.h>
#include <ESPAsyncWebServer.h>

const char *ssid = "hi";
const char *password = "12345678";

String currentDirectory = "/";  // Carpeta inicial en SPIFFS

AsyncWebServer server(80);

void setup() {
  Serial.begin(115200);

  if (!SPIFFS.begin()) {
    Serial.println("No se pudo inicializar SPIFFS.");
    return;
  }

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Conectando a WiFi...");
  }

  Serial.println("Conexión exitosa al WiFi");
  Serial.print("Dirección IP: ");
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    String html = "<html><body>";
    html += "<h1>ESP32 SPIFFS Web Server</h1>";
    html += "<p>Conexión exitosa al WiFi</p>";
    html += "<p>Dirección IP: " + WiFi.localIP().toString() + "</p>";
    html += "<p>SPIFFS Inicializado</p>";
    html += "<form action=\"/changeDirectory\" method=\"post\">";
    html += "   <label for=\"directory\">Carpeta Actual: " + currentDirectory + "</label><br>";
    html += "   <input type=\"text\" id=\"directory\" name=\"directory\" placeholder=\"Ingrese nueva carpeta\">";
    html += "   <input type=\"submit\" value=\"Cambiar Carpeta\">";
    html += "</form>";
    html += "<button onclick=\"listFiles()\">Listar Archivos</button>";
    html += "<input type=\"file\" id=\"fileInput\" multiple/>";
    html += "<button onclick=\"uploadFiles()\">Subir Archivos</button>";
    html += "<button onclick=\"deleteSelectedFiles()\">Eliminar Archivos Seleccionados</button>";
    html += "<button onclick=\"goHome()\">Home</button>";
    html += "<script>function listFiles(){fetch('/list').then(response => response.text()).then(data => document.getElementById('fileList').innerHTML = data);} function uploadFiles(){var fileInput = document.getElementById('fileInput'); var formData = new FormData(); for (var i = 0; i < fileInput.files.length; i++) { formData.append('file[]', fileInput.files[i]); } fetch('/upload', {method: 'POST', body: formData}).then(listFiles);} function deleteSelectedFiles(){if(confirm('¿Está seguro de que desea eliminar los archivos seleccionados?')){var checkboxes = document.querySelectorAll('input[type=\"checkbox\"]:checked'); var formData = new FormData(); checkboxes.forEach(function(checkbox){formData.append('file', checkbox.value);}); fetch('/delete', {method: 'POST', body: formData}).then(response => response.text()).then(data => alert(data)).then(listFiles);}}";
    html += "function goHome(){fetch('/goHome').then(response => response.text()).then(data => alert(data)).then(listFiles);}</script>";
    html += "<div id=\"fileList\"></div>";
    html += "<script>listFiles();</script>";  // Agregado: listar archivos automáticamente al cargar la página
    html += "</body></html>";
    request->send(200, "text/html", html);
  });

  server.on("/upload", HTTP_POST, [](AsyncWebServerRequest *request) {
    AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Archivos Subidos");
    response->addHeader("Connection", "close");
    request->send(response);
  },
             [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
               static File uploadFile;

               if (!index) {
                 uploadFile = SPIFFS.open(currentDirectory + "/" + filename, FILE_WRITE);
               }
               if (uploadFile) {
                 for (size_t i = 0; i < len; i++) {
                   uploadFile.write(data[i]);
                 }
               }
               if (final) {
                 uploadFile.close();
                 Serial.printf("Archivo %s subido con éxito.\n", filename.c_str());
               }
             });

  server.on("/list", HTTP_GET, [](AsyncWebServerRequest *request) {
    String files;
    File dir = SPIFFS.open(currentDirectory);
    while (File entry = dir.openNextFile()) {
      String previewPath = generatePreview(entry.name());
      files += "<p><input type=\"checkbox\" name=\"file\" value=\"" + String(entry.name()) + "\"> " + entry.name() + "<br><img src=\"" + previewPath + "\" width=\"100\"></p>";
      entry.close();
    }
    request->send(200, "text/html", files);
  });

  server.on("/delete", HTTP_POST, [](AsyncWebServerRequest *request) {
    String responseMessage = deleteSelectedFiles(request);
    request->send(200, "text/plain", responseMessage);
  });

  server.on("/changeDirectory", HTTP_POST, [](AsyncWebServerRequest *request){
    if(request->hasParam("directory", true)){
      currentDirectory = "/" + request->getParam("directory", true)->value();
    }
    request->redirect("/");
  });

  server.on("/goHome", HTTP_GET, [](AsyncWebServerRequest *request){
    currentDirectory = "/";
    request->send(200, "text/plain", "Ir a la carpeta raíz.");
  });

  server.on("/preview", HTTP_GET, [](AsyncWebServerRequest *request){
    servePreview(request);
  });

  Serial.println("ESP32 SPIFFS Web Server iniciado.");
  server.begin();
}

void loop() {
  // Nada que hacer aquí
}

String deleteSelectedFiles(AsyncWebServerRequest *request) {
  String responseMessage = "Archivos seleccionados eliminados con éxito";
  int params = request->params();
  for (int i = 0; i < params; i++) {
    AsyncWebParameter* p = request->getParam(i);
    if (p->name() == "file") {
      SPIFFS.remove(currentDirectory + "/" + p->value());
      Serial.printf("Archivo %s eliminado con éxito.\n", p->value().c_str());
    }
  }
  return responseMessage;
}

String generatePreview(String filename) {
  if (filename.endsWith(".gif")) {
    return "/preview?file=" + filename;
  }
  // Si el archivo no es un GIF, simplemente devolver una cadena vacía
  return "";
}

void servePreview(AsyncWebServerRequest *request) {
  if (request->hasParam("file")) {
    String filename = request->getParam("file")->value();
    String filePath = currentDirectory + "/" + filename;
    if (SPIFFS.exists(filePath)) {
      AsyncWebServerResponse *response = request->beginResponse(SPIFFS, filePath, "image/gif");
      request->send(response);
    } else {
      request->send(404, "text/plain", "Archivo no encontrado");
    }
  } else {
    request->send(400, "text/plain", "Parámetro 'file' faltante");
  }
}

//GIF SPIFFS player
// Example sketch which shows how to display a 64x32 animated GIF image stored in FLASH memory
// on a 64x32 LED matrix
//
// Credits: https://github.com/bitbank2/AnimatedGIF/tree/master/examples/ESP32_LEDMatrix_I2S
// 

/* INSTRUCTIONS
 *
 * 1. First Run the 'ESP32 Sketch Data Upload Tool' in Arduino from the 'Tools' Menu.
 *    - If you don't know what this is or see it as an option, then read this:
 *      https://github.com/me-no-dev/arduino-esp32fs-plugin 
 *    - This tool will upload the contents of the data/ directory in the sketch folder onto
 *      the ESP32 itself.
 *
 * 2. You can drop any animated GIF you want in there, but keep it to the resolution of the 
 *    MATRIX you're displaying to. To resize a gif, use this online website: https://ezgif.com/
 *
 * 3. Have fun.
 */

#define FILESYSTEM SPIFFS
#include <SPIFFS.h>
#include <AnimatedGIF.h>
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
#define A_PIN   33  
#define B_PIN   32  
#define C_PIN   22   
#define E_PIN   21 

#define PANEL_RES_X 64      // Number of pixels wide of each INDIVIDUAL panel module. 
#define PANEL_RES_Y 64    // Number of pixels tall of each INDIVIDUAL panel module.
#define PANEL_CHAIN 1      // Total number of panels chained one to another
 
//MatrixPanel_I2S_DMA dma_display;
MatrixPanel_I2S_DMA *dma_display = nullptr;

uint16_t myBLACK = dma_display->color565(0, 0, 0);
uint16_t myWHITE = dma_display->color565(255, 255, 255);
uint16_t myRED = dma_display->color565(255, 0, 0);
uint16_t myGREEN = dma_display->color565(0, 255, 0);
uint16_t myBLUE = dma_display->color565(0, 0, 255);


AnimatedGIF gif;
File f;
int x_offset, y_offset;



// Draw a line of image directly on the LED Matrix
void GIFDraw(GIFDRAW *pDraw)
{
    uint8_t *s;
    uint16_t *d, *usPalette, usTemp[320];
    int x, y, iWidth;

  iWidth = pDraw->iWidth;
  if (iWidth > MATRIX_WIDTH)
      iWidth = MATRIX_WIDTH;

    usPalette = pDraw->pPalette;
    y = pDraw->iY + pDraw->y; // current line
    
    s = pDraw->pPixels;
    if (pDraw->ucDisposalMethod == 2) // restore to background color
    {
      for (x=0; x<iWidth; x++)
      {
        if (s[x] == pDraw->ucTransparent)
           s[x] = pDraw->ucBackground;
      }
      pDraw->ucHasTransparency = 0;
    }
    // Apply the new pixels to the main image
    if (pDraw->ucHasTransparency) // if transparency used
    {
      uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent;
      int x, iCount;
      pEnd = s + pDraw->iWidth;
      x = 0;
      iCount = 0; // count non-transparent pixels
      while(x < pDraw->iWidth)
      {
        c = ucTransparent-1;
        d = usTemp;
        while (c != ucTransparent && s < pEnd)
        {
          c = *s++;
          if (c == ucTransparent) // done, stop
          {
            s--; // back up to treat it like transparent
          }
          else // opaque
          {
             *d++ = usPalette[c];
             iCount++;
          }
        } // while looking for opaque pixels
        if (iCount) // any opaque pixels?
        {
          for(int xOffset = 0; xOffset < iCount; xOffset++ ){
            dma_display->drawPixel(x + xOffset, y, usTemp[xOffset]); // 565 Color Format
          }
          x += iCount;
          iCount = 0;
        }
        // no, look for a run of transparent pixels
        c = ucTransparent;
        while (c == ucTransparent && s < pEnd)
        {
          c = *s++;
          if (c == ucTransparent)
             iCount++;
          else
             s--; 
        }
        if (iCount)
        {
          x += iCount; // skip these
          iCount = 0;
        }
      }
    }
    else // does not have transparency
    {
      s = pDraw->pPixels;
      // Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
      for (x=0; x<pDraw->iWidth; x++)
      {
        dma_display->drawPixel(x, y, usPalette[*s++]); // color 565
      }
    }
} /* GIFDraw() */


void * GIFOpenFile(const char *fname, int32_t *pSize)
{
  Serial.print("Playing gif: ");
  Serial.println(fname);
  f = FILESYSTEM.open(fname);
  if (f)
  {
    *pSize = f.size();
    return (void *)&f;
  }
  return NULL;
} /* GIFOpenFile() */

void GIFCloseFile(void *pHandle)
{
  File *f = static_cast<File *>(pHandle);
  if (f != NULL)
     f->close();
} /* GIFCloseFile() */

int32_t GIFReadFile(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen)
{
    int32_t iBytesRead;
    iBytesRead = iLen;
    File *f = static_cast<File *>(pFile->fHandle);
    // Note: If you read a file all the way to the last byte, seek() stops working
    if ((pFile->iSize - pFile->iPos) < iLen)
       iBytesRead = pFile->iSize - pFile->iPos - 1; // <-- ugly work-around
    if (iBytesRead <= 0)
       return 0;
    iBytesRead = (int32_t)f->read(pBuf, iBytesRead);
    pFile->iPos = f->position();
    return iBytesRead;
} /* GIFReadFile() */

int32_t GIFSeekFile(GIFFILE *pFile, int32_t iPosition)
{ 
  int i = micros();
  File *f = static_cast<File *>(pFile->fHandle);
  f->seek(iPosition);
  pFile->iPos = (int32_t)f->position();
  i = micros() - i;
//  Serial.printf("Seek time = %d us\n", i);
  return pFile->iPos;
} /* GIFSeekFile() */

unsigned long start_tick = 0;

void ShowGIF(char *name)
{
  start_tick = millis();
   
  if (gif.open(name, GIFOpenFile, GIFCloseFile, GIFReadFile, GIFSeekFile, GIFDraw))
  {
    x_offset = (MATRIX_WIDTH - gif.getCanvasWidth())/2;
    if (x_offset < 0) x_offset = 0;
    y_offset = (MATRIX_HEIGHT - gif.getCanvasHeight())/2;
    if (y_offset < 0) y_offset = 0;
    Serial.printf("Successfully opened GIF; Canvas size = %d x %d\n", gif.getCanvasWidth(), gif.getCanvasHeight());
    Serial.flush();
    while (gif.playFrame(true, NULL))
    {      
      if ( (millis() - start_tick) > 8000) { // we'll get bored after about 8 seconds of the same looping gif
        break;
      }
    }
    gif.close();
  }

} /* ShowGIF() */



/************************* Arduino Sketch Setup and Loop() *******************************/
void setup() {
  Serial.begin(115200);
  delay(1000);

  HUB75_I2S_CFG mxconfig(
    PANEL_RES_X,   // module width
    PANEL_RES_Y,   // module height
    PANEL_CHAIN    // Chain length
  );

    mxconfig.gpio.a = A_PIN;
    mxconfig.gpio.b = B_PIN;
    mxconfig.gpio.c = C_PIN;
    mxconfig.gpio.e = E_PIN;    
    mxconfig.clkphase = false;

  //mxconfig.driver = HUB75_I2S_CFG::FM6126A;

  // Display Setup
  dma_display = new MatrixPanel_I2S_DMA(mxconfig);
  dma_display->begin();
  dma_display->setBrightness8(128); //0-255
  dma_display->clearScreen();
  dma_display->fillScreen(myWHITE);

  Serial.println("Starting AnimatedGIFs Sketch");

  // Start filesystem
  Serial.println(" * Loading SPIFFS");
  if(!SPIFFS.begin()){
        Serial.println("SPIFFS Mount Failed");
  }
  
  dma_display->begin();
  
  /* all other pixel drawing functions can only be called after .begin() */
  dma_display->fillScreen(dma_display->color565(0, 0, 0));
  gif.begin(LITTLE_ENDIAN_PIXELS);

}

String gifDir = "/"; // play all GIFs in this directory on the SD card
char filePath[256] = { 0 };
File root, gifFile;

void loop() 
{
   while (1) // run forever
   {
      
      root = FILESYSTEM.open(gifDir);
      if (root)
      {
           gifFile = root.openNextFile();
            while (gifFile)
            {
              if (!gifFile.isDirectory()) // play it
              {
                
                // C-strings... urghh...                
                memset(filePath, 0x0, sizeof(filePath));                
                strcpy(filePath, gifFile.path());
                
                // Show it.
                ShowGIF(filePath);
               
              }
              gifFile.close();
              gifFile = root.openNextFile();
            }
         root.close();
      } // root
      
      delay(1000); // pause before restarting
      
   } // while
}

That is a very bad description of the problem. Does the sketch work when not combined with the other one or does it never work ? What exactly does "doesn't work" mean anyway ?

I want to join the 2 codes but only the gif player works but the server does not load

So both sketches work when used alone but the server does not work when you combine them together

Please post your best effort at combining them

My combined code, was wrong?

#define FILESYSTEM SPIFFS
#include <SPIFFS.h>
#include <AnimatedGIF.h>
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
#include <Arduino.h>
#include <FS.h>
#include <ESPAsyncWebServer.h>

#define A_PIN   33  
#define B_PIN   32  
#define C_PIN   22   
#define E_PIN   21 

#define PANEL_RES_X 64      // Number of pixels wide of each INDIVIDUAL panel module. 
#define PANEL_RES_Y 64    // Number of pixels tall of each INDIVIDUAL panel module.
#define PANEL_CHAIN 1      // Total number of panels chained one to another

const char *ssid = "hi";
const char *password = "12345678";

String currentDirectory = "/";  // Carpeta inicial en SPIFFS

AsyncWebServer server(80);


//MatrixPanel_I2S_DMA dma_display;
MatrixPanel_I2S_DMA *dma_display = nullptr;

uint16_t myBLACK = dma_display->color565(0, 0, 0);
uint16_t myWHITE = dma_display->color565(255, 255, 255);
uint16_t myRED = dma_display->color565(255, 0, 0);
uint16_t myGREEN = dma_display->color565(0, 255, 0);
uint16_t myBLUE = dma_display->color565(0, 0, 255);


AnimatedGIF gif;
File f;
int x_offset, y_offset;


// Draw a line of image directly on the LED Matrix
void GIFDraw(GIFDRAW *pDraw)
{
    uint8_t *s;
    uint16_t *d, *usPalette, usTemp[320];
    int x, y, iWidth;

  iWidth = pDraw->iWidth;
  if (iWidth > MATRIX_WIDTH)
      iWidth = MATRIX_WIDTH;

    usPalette = pDraw->pPalette;
    y = pDraw->iY + pDraw->y; // current line
    
    s = pDraw->pPixels;
    if (pDraw->ucDisposalMethod == 2) // restore to background color
    {
      for (x=0; x<iWidth; x++)
      {
        if (s[x] == pDraw->ucTransparent)
           s[x] = pDraw->ucBackground;
      }
      pDraw->ucHasTransparency = 0;
    }
    // Apply the new pixels to the main image
    if (pDraw->ucHasTransparency) // if transparency used
    {
      uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent;
      int x, iCount;
      pEnd = s + pDraw->iWidth;
      x = 0;
      iCount = 0; // count non-transparent pixels
      while(x < pDraw->iWidth)
      {
        c = ucTransparent-1;
        d = usTemp;
        while (c != ucTransparent && s < pEnd)
        {
          c = *s++;
          if (c == ucTransparent) // done, stop
          {
            s--; // back up to treat it like transparent
          }
          else // opaque
          {
             *d++ = usPalette[c];
             iCount++;
          }
        } // while looking for opaque pixels
        if (iCount) // any opaque pixels?
        {
          for(int xOffset = 0; xOffset < iCount; xOffset++ ){
            dma_display->drawPixel(x + xOffset, y, usTemp[xOffset]); // 565 Color Format
          }
          x += iCount;
          iCount = 0;
        }
        // no, look for a run of transparent pixels
        c = ucTransparent;
        while (c == ucTransparent && s < pEnd)
        {
          c = *s++;
          if (c == ucTransparent)
             iCount++;
          else
             s--; 
        }
        if (iCount)
        {
          x += iCount; // skip these
          iCount = 0;
        }
      }
    }
    else // does not have transparency
    {
      s = pDraw->pPixels;
      // Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
      for (x=0; x<pDraw->iWidth; x++)
      {
        dma_display->drawPixel(x, y, usPalette[*s++]); // color 565
      }
    }
} /* GIFDraw() */


void * GIFOpenFile(const char *fname, int32_t *pSize)
{
  Serial.print("Playing gif: ");
  Serial.println(fname);
  f = FILESYSTEM.open(fname);
  if (f)
  {
    *pSize = f.size();
    return (void *)&f;
  }
  return NULL;
} /* GIFOpenFile() */

void GIFCloseFile(void *pHandle)
{
  File *f = static_cast<File *>(pHandle);
  if (f != NULL)
     f->close();
} /* GIFCloseFile() */

int32_t GIFReadFile(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen)
{
    int32_t iBytesRead;
    iBytesRead = iLen;
    File *f = static_cast<File *>(pFile->fHandle);
    // Note: If you read a file all the way to the last byte, seek() stops working
    if ((pFile->iSize - pFile->iPos) < iLen)
       iBytesRead = pFile->iSize - pFile->iPos - 1; // <-- ugly work-around
    if (iBytesRead <= 0)
       return 0;
    iBytesRead = (int32_t)f->read(pBuf, iBytesRead);
    pFile->iPos = f->position();
    return iBytesRead;
} /* GIFReadFile() */

int32_t GIFSeekFile(GIFFILE *pFile, int32_t iPosition)
{ 
  int i = micros();
  File *f = static_cast<File *>(pFile->fHandle);
  f->seek(iPosition);
  pFile->iPos = (int32_t)f->position();
  i = micros() - i;
//  Serial.printf("Seek time = %d us\n", i);
  return pFile->iPos;
} /* GIFSeekFile() */

unsigned long start_tick = 0;

void ShowGIF(char *name)
{
  start_tick = millis();
   
  if (gif.open(name, GIFOpenFile, GIFCloseFile, GIFReadFile, GIFSeekFile, GIFDraw))
  {
    x_offset = (MATRIX_WIDTH - gif.getCanvasWidth())/2;
    if (x_offset < 0) x_offset = 0;
    y_offset = (MATRIX_HEIGHT - gif.getCanvasHeight())/2;
    if (y_offset < 0) y_offset = 0;
    Serial.printf("Successfully opened GIF; Canvas size = %d x %d\n", gif.getCanvasWidth(), gif.getCanvasHeight());
    Serial.flush();
    while (gif.playFrame(true, NULL))
    {      
      if ( (millis() - start_tick) > 8000) { // we'll get bored after about 8 seconds of the same looping gif
        break;
      }
    }
    gif.close();
  }

} /* ShowGIF() */



/************************* Arduino Sketch Setup and Loop() *******************************/
void setup() {
  Serial.begin(115200);
  delay(1000);

  HUB75_I2S_CFG mxconfig(
    PANEL_RES_X,   // module width
    PANEL_RES_Y,   // module height
    PANEL_CHAIN    // Chain length
  );

    mxconfig.gpio.a = A_PIN;
    mxconfig.gpio.b = B_PIN;
    mxconfig.gpio.c = C_PIN;
    mxconfig.gpio.e = E_PIN;    
    mxconfig.clkphase = false;

  //mxconfig.driver = HUB75_I2S_CFG::FM6126A;

  // Display Setup
  dma_display = new MatrixPanel_I2S_DMA(mxconfig);
  dma_display->begin();
  dma_display->setBrightness8(128); //0-255
  dma_display->clearScreen();
  dma_display->fillScreen(myWHITE);

  Serial.println("Starting AnimatedGIFs Sketch");

  // Start filesystem
  Serial.println(" * Loading SPIFFS");
  if(!SPIFFS.begin()){
        Serial.println("SPIFFS Mount Failed");
  }
  
  dma_display->begin();
  
  /* all other pixel drawing functions can only be called after .begin() */
  dma_display->fillScreen(dma_display->color565(0, 0, 0));
  gif.begin(LITTLE_ENDIAN_PIXELS);


if (!SPIFFS.begin()) {
    Serial.println("No se pudo inicializar SPIFFS.");
    return;
  }

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Conectando a WiFi...");
  }

  Serial.println("Conexión exitosa al WiFi");
  Serial.print("Dirección IP: ");
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    String html = "<html><body>";
    html += "<h1>ESP32 SPIFFS Web Server</h1>";
    html += "<p>Conexión exitosa al WiFi</p>";
    html += "<p>Dirección IP: " + WiFi.localIP().toString() + "</p>";
    html += "<p>SPIFFS Inicializado</p>";
    html += "<form action=\"/changeDirectory\" method=\"post\">";
    html += "   <label for=\"directory\">Carpeta Actual: " + currentDirectory + "</label><br>";
    html += "   <input type=\"text\" id=\"directory\" name=\"directory\" placeholder=\"Ingrese nueva carpeta\">";
    html += "   <input type=\"submit\" value=\"Cambiar Carpeta\">";
    html += "</form>";
    html += "<button onclick=\"listFiles()\">Listar Archivos</button>";
    html += "<input type=\"file\" id=\"fileInput\" multiple/>";
    html += "<button onclick=\"uploadFiles()\">Subir Archivos</button>";
    html += "<button onclick=\"deleteSelectedFiles()\">Eliminar Archivos Seleccionados</button>";
    html += "<button onclick=\"goHome()\">Home</button>";
    html += "<script>function listFiles(){fetch('/list').then(response => response.text()).then(data => document.getElementById('fileList').innerHTML = data);} function uploadFiles(){var fileInput = document.getElementById('fileInput'); var formData = new FormData(); for (var i = 0; i < fileInput.files.length; i++) { formData.append('file[]', fileInput.files[i]); } fetch('/upload', {method: 'POST', body: formData}).then(listFiles);} function deleteSelectedFiles(){if(confirm('¿Está seguro de que desea eliminar los archivos seleccionados?')){var checkboxes = document.querySelectorAll('input[type=\"checkbox\"]:checked'); var formData = new FormData(); checkboxes.forEach(function(checkbox){formData.append('file', checkbox.value);}); fetch('/delete', {method: 'POST', body: formData}).then(response => response.text()).then(data => alert(data)).then(listFiles);}}";
    html += "function goHome(){fetch('/goHome').then(response => response.text()).then(data => alert(data)).then(listFiles);}</script>";
    html += "<div id=\"fileList\"></div>";
    html += "<script>listFiles();</script>";  // Agregado: listar archivos automáticamente al cargar la página
    html += "</body></html>";
    request->send(200, "text/html", html);
  });

  server.on("/upload", HTTP_POST, [](AsyncWebServerRequest *request) {
    AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Archivos Subidos");
    response->addHeader("Connection", "close");
    request->send(response);
  },
             [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
               static File uploadFile;

               if (!index) {
                 uploadFile = SPIFFS.open(currentDirectory + "/" + filename, FILE_WRITE);
               }
               if (uploadFile) {
                 for (size_t i = 0; i < len; i++) {
                   uploadFile.write(data[i]);
                 }
               }
               if (final) {
                 uploadFile.close();
                 Serial.printf("Archivo %s subido con éxito.\n", filename.c_str());
               }
             });

  server.on("/list", HTTP_GET, [](AsyncWebServerRequest *request) {
    String files;
    File dir = SPIFFS.open(currentDirectory);
    while (File entry = dir.openNextFile()) {
      String previewPath = generatePreview(entry.name());
      files += "<p><input type=\"checkbox\" name=\"file\" value=\"" + String(entry.name()) + "\"> " + entry.name() + "<br><img src=\"" + previewPath + "\" width=\"100\"></p>";
      entry.close();
    }
    request->send(200, "text/html", files);
  });

  server.on("/delete", HTTP_POST, [](AsyncWebServerRequest *request) {
    String responseMessage = deleteSelectedFiles(request);
    request->send(200, "text/plain", responseMessage);
  });

  server.on("/changeDirectory", HTTP_POST, [](AsyncWebServerRequest *request){
    if(request->hasParam("directory", true)){
      currentDirectory = "/" + request->getParam("directory", true)->value();
    }
    request->redirect("/");
  });

  server.on("/goHome", HTTP_GET, [](AsyncWebServerRequest *request){
    currentDirectory = "/";
    request->send(200, "text/plain", "Ir a la carpeta raíz.");
  });

  server.on("/preview", HTTP_GET, [](AsyncWebServerRequest *request){
    servePreview(request);
  });

  Serial.println("ESP32 SPIFFS Web Server iniciado.");
  server.begin();
}

String gifDir = "/"; // play all GIFs in this directory on the SD card
char filePath[256] = { 0 };
File root, gifFile;

void loop() 
{
   while (1) // run forever
   {
      
      root = FILESYSTEM.open(gifDir);
      if (root)
      {
           gifFile = root.openNextFile();
            while (gifFile)
            {
              if (!gifFile.isDirectory()) // play it
              {
                
                // C-strings... urghh...                
                memset(filePath, 0x0, sizeof(filePath));                
                strcpy(filePath, gifFile.path());
                
                // Show it.
                ShowGIF(filePath);
               
              }
              gifFile.close();
              gifFile = root.openNextFile();
            }
         root.close();
      } // root
      
      delay(1000); // pause before restarting
      
   } // while
}

String deleteSelectedFiles(AsyncWebServerRequest *request) {
  String responseMessage = "Archivos seleccionados eliminados con éxito";
  int params = request->params();
  for (int i = 0; i < params; i++) {
    AsyncWebParameter* p = request->getParam(i);
    if (p->name() == "file") {
      SPIFFS.remove(currentDirectory + "/" + p->value());
      Serial.printf("Archivo %s eliminado con éxito.\n", p->value().c_str());
    }
  }
  return responseMessage;
}

String generatePreview(String filename) {
  if (filename.endsWith(".gif")) {
    return "/preview?file=" + filename;
  }
  // Si el archivo no es un GIF, simplemente devolver una cadena vacía
  return "";
}

void servePreview(AsyncWebServerRequest *request) {
  if (request->hasParam("file")) {
    String filename = request->getParam("file")->value();
    String filePath = currentDirectory + "/" + filename;
    if (SPIFFS.exists(filePath)) {
      AsyncWebServerResponse *response = request->beginResponse(SPIFFS, filePath, "image/gif");
      request->send(response);
    } else {
      request->send(404, "text/plain", "Archivo no encontrado");
    }
  } else {
    request->send(400, "text/plain", "Parámetro 'file' faltante");
  }
}

The very best approach is to start with one of the programs, making sure it works as expected, and add one feature at a time to it, testing for correct function as you go.

but the one from the web server doesn't work

Start with the other one, then.

I get it working using function

#include <Arduino.h>
#include <FS.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>

#define FILESYSTEM SPIFFS
#include <AnimatedGIF.h>
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
#define A_PIN   33  
#define B_PIN   32  
#define C_PIN   22   
#define E_PIN   21 

#define PANEL_RES_X 64      // Number of pixels wide of each INDIVIDUAL panel module. 
#define PANEL_RES_Y 64    // Number of pixels tall of each INDIVIDUAL panel module.
#define PANEL_CHAIN 1      // Total number of panels chained one to another
 
//MatrixPanel_I2S_DMA dma_display;
MatrixPanel_I2S_DMA *dma_display = nullptr;

uint16_t myBLACK = dma_display->color565(0, 0, 0);
uint16_t myWHITE = dma_display->color565(255, 255, 255);
uint16_t myRED = dma_display->color565(255, 0, 0);
uint16_t myGREEN = dma_display->color565(0, 255, 0);
uint16_t myBLUE = dma_display->color565(0, 0, 255);


AnimatedGIF gif;
File f;
int x_offset, y_offset;


const char *ssid = "hi";
const char *password = "12345678";

String currentDirectory = "/";  // Carpeta inicial

AsyncWebServer server(80);



void setup() {
  Serial.begin(115200);

  if (!SPIFFS.begin()) {
    Serial.println("No se pudo inicializar SPIFFS.");
    return;
  }

  servidor();
  setupGIF();
}
void servidor(){

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Conectando a WiFi...");
  }

  Serial.println("Conexión exitosa al WiFi");
  Serial.print("Dirección IP: ");
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    String html = "<html><body>";
    html += "<h1>ESP32 SPIFFS Web Server</h1>";
    html += "<p>Conexión exitosa al WiFi</p>";
    html += "<p>Dirección IP: " + WiFi.localIP().toString() + "</p>";
    html += "<p>SPIFFS Montado</p>";
    html += "<form action=\"/changeDirectory\" method=\"post\">";
    html += "   <label for=\"directory\">Carpeta Actual: " + currentDirectory + "</label><br>";
    html += "   <input type=\"text\" id=\"directory\" name=\"directory\" placeholder=\"Ingrese nueva carpeta\">";
    html += "   <input type=\"submit\" value=\"Cambiar Carpeta\">";
    html += "</form>";
    html += "<button onclick=\"listFiles()\">Listar Archivos</button>";
    html += "<input type=\"file\" id=\"fileInput\" multiple/>";
    html += "<button onclick=\"uploadFiles()\">Subir Archivos</button>";
    html += "<button onclick=\"deleteSelectedFiles()\">Eliminar Archivos Seleccionados</button>";
    html += "<button onclick=\"goHome()\">Home</button>";
    html += "<script>function listFiles(){fetch('/list').then(response => response.text()).then(data => document.getElementById('fileList').innerHTML = data);} function uploadFiles(){var fileInput = document.getElementById('fileInput'); var formData = new FormData(); for (var i = 0; i < fileInput.files.length; i++) { formData.append('file[]', fileInput.files[i]); } fetch('/upload', {method: 'POST', body: formData}).then(listFiles);} function deleteSelectedFiles(){if(confirm('¿Está seguro de que desea eliminar los archivos seleccionados?')){var checkboxes = document.querySelectorAll('input[type=\"checkbox\"]:checked'); var formData = new FormData(); checkboxes.forEach(function(checkbox){formData.append('file', checkbox.value);}); fetch('/delete', {method: 'POST', body: formData}).then(response => response.text()).then(data => alert(data)).then(listFiles);}}";
    html += "function goHome(){fetch('/goHome').then(response => response.text()).then(data => alert(data)).then(listFiles);}</script>";
    html += "<div id=\"fileList\"></div>";
    html += "<script>listFiles();</script>";  // Agregado: listar archivos automáticamente al cargar la página
    html += "</body></html>";
    request->send(200, "text/html", html);
  });

  server.on("/upload", HTTP_POST, [](AsyncWebServerRequest *request) {
    AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Archivos Subidos");
    response->addHeader("Connection", "close");
    request->send(response);
  },
             [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
               static File uploadFile;

               if (!index) {
                 uploadFile = SPIFFS.open(currentDirectory + "/" + filename, FILE_WRITE);
               }
               if (uploadFile) {
                 for (size_t i = 0; i < len; i++) {
                   uploadFile.write(data[i]);
                 }
               }
               if (final) {
                 uploadFile.close();
                 Serial.printf("Archivo %s subido con éxito.\n", filename.c_str());
               }
             });

  server.on("/list", HTTP_GET, [](AsyncWebServerRequest *request) {
    String files;
    File dir = SPIFFS.open(currentDirectory);
    File entry = dir.openNextFile();
    while (entry) {
      String previewPath = generatePreview(entry.name());
      files += "<p><input type=\"checkbox\" name=\"file\" value=\"" + String(entry.name()) + "\"> " + entry.name() + "<br><img src=\"" + previewPath + "\" width=\"100\"></p>";
      entry = dir.openNextFile();
    }
    request->send(200, "text/html", files);
  });

  server.on("/delete", HTTP_POST, [](AsyncWebServerRequest *request) {
    String responseMessage = deleteSelectedFiles(request);
    request->send(200, "text/plain", responseMessage);
  });

  server.on("/changeDirectory", HTTP_POST, [](AsyncWebServerRequest *request){
    if(request->hasParam("directory", true)){
      currentDirectory = "/" + request->getParam("directory", true)->value();
    }
    request->redirect("/");
  });

  server.on("/goHome", HTTP_GET, [](AsyncWebServerRequest *request){
    currentDirectory = "/";
    request->send(200, "text/plain", "Ir a la carpeta raíz.");
  });

  server.on("/preview", HTTP_GET, [](AsyncWebServerRequest *request){
    servePreview(request);
  });

  Serial.println("ESP32 SPIFFS Web Server iniciado.");
  server.begin();

}

String deleteSelectedFiles(AsyncWebServerRequest *request) {
  String responseMessage = "Archivos seleccionados eliminados con éxito";
  int params = request->params();
  for (int i = 0; i < params; i++) {
    AsyncWebParameter* p = request->getParam(i);
    if (p->name() == "file") {
      SPIFFS.remove(currentDirectory + "/" + p->value());
      Serial.printf("Archivo %s eliminado con éxito.\n", p->value().c_str());
    }
  }
  return responseMessage;
}

String generatePreview(String filename) {
  if (filename.endsWith(".gif")) {
    return "/preview?file=" + filename;
  }
  // Si el archivo no es un GIF, simplemente devolver una cadena vacía
  return "";
}

void servePreview(AsyncWebServerRequest *request) {
  if (request->hasParam("file")) {
    String filename = request->getParam("file")->value();
    String filePath = currentDirectory + "/" + filename;
    if (SPIFFS.exists(filePath)) {
      AsyncWebServerResponse *response = request->beginResponse(SPIFFS, filePath, "image/gif");
      request->send(response);
    } else {
      request->send(404, "text/plain", "Archivo no encontrado");
    }
  } else {
    request->send(400, "text/plain", "Parámetro 'file' faltante");
  }
}
// Draw a line of image directly on the LED Matrix
void GIFDraw(GIFDRAW *pDraw)
{
    uint8_t *s;
    uint16_t *d, *usPalette, usTemp[320];
    int x, y, iWidth;

  iWidth = pDraw->iWidth;
  if (iWidth > MATRIX_WIDTH)
      iWidth = MATRIX_WIDTH;

    usPalette = pDraw->pPalette;
    y = pDraw->iY + pDraw->y; // current line
    
    s = pDraw->pPixels;
    if (pDraw->ucDisposalMethod == 2) // restore to background color
    {
      for (x=0; x<iWidth; x++)
      {
        if (s[x] == pDraw->ucTransparent)
           s[x] = pDraw->ucBackground;
      }
      pDraw->ucHasTransparency = 0;
    }
    // Apply the new pixels to the main image
    if (pDraw->ucHasTransparency) // if transparency used
    {
      uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent;
      int x, iCount;
      pEnd = s + pDraw->iWidth;
      x = 0;
      iCount = 0; // count non-transparent pixels
      while(x < pDraw->iWidth)
      {
        c = ucTransparent-1;
        d = usTemp;
        while (c != ucTransparent && s < pEnd)
        {
          c = *s++;
          if (c == ucTransparent) // done, stop
          {
            s--; // back up to treat it like transparent
          }
          else // opaque
          {
             *d++ = usPalette[c];
             iCount++;
          }
        } // while looking for opaque pixels
        if (iCount) // any opaque pixels?
        {
          for(int xOffset = 0; xOffset < iCount; xOffset++ ){
            dma_display->drawPixel(x + xOffset, y, usTemp[xOffset]); // 565 Color Format
          }
          x += iCount;
          iCount = 0;
        }
        // no, look for a run of transparent pixels
        c = ucTransparent;
        while (c == ucTransparent && s < pEnd)
        {
          c = *s++;
          if (c == ucTransparent)
             iCount++;
          else
             s--; 
        }
        if (iCount)
        {
          x += iCount; // skip these
          iCount = 0;
        }
      }
    }
    else // does not have transparency
    {
      s = pDraw->pPixels;
      // Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
      for (x=0; x<pDraw->iWidth; x++)
      {
        dma_display->drawPixel(x, y, usPalette[*s++]); // color 565
      }
    }
} /* GIFDraw() */


void * GIFOpenFile(const char *fname, int32_t *pSize)
{
  Serial.print("Playing gif: ");
  Serial.println(fname);
  f = FILESYSTEM.open(fname);
  if (f)
  {
    *pSize = f.size();
    return (void *)&f;
  }
  return NULL;
} /* GIFOpenFile() */

void GIFCloseFile(void *pHandle)
{
  File *f = static_cast<File *>(pHandle);
  if (f != NULL)
     f->close();
} /* GIFCloseFile() */

int32_t GIFReadFile(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen)
{
    int32_t iBytesRead;
    iBytesRead = iLen;
    File *f = static_cast<File *>(pFile->fHandle);
    // Note: If you read a file all the way to the last byte, seek() stops working
    if ((pFile->iSize - pFile->iPos) < iLen)
       iBytesRead = pFile->iSize - pFile->iPos - 1; // <-- ugly work-around
    if (iBytesRead <= 0)
       return 0;
    iBytesRead = (int32_t)f->read(pBuf, iBytesRead);
    pFile->iPos = f->position();
    return iBytesRead;
} /* GIFReadFile() */

int32_t GIFSeekFile(GIFFILE *pFile, int32_t iPosition)
{ 
  int i = micros();
  File *f = static_cast<File *>(pFile->fHandle);
  f->seek(iPosition);
  pFile->iPos = (int32_t)f->position();
  i = micros() - i;
//  Serial.printf("Seek time = %d us\n", i);
  return pFile->iPos;
} /* GIFSeekFile() */

unsigned long start_tick = 0;

void ShowGIF(char *name)
{
  start_tick = millis();
   
  if (gif.open(name, GIFOpenFile, GIFCloseFile, GIFReadFile, GIFSeekFile, GIFDraw))
  {
    x_offset = (MATRIX_WIDTH - gif.getCanvasWidth())/2;
    if (x_offset < 0) x_offset = 0;
    y_offset = (MATRIX_HEIGHT - gif.getCanvasHeight())/2;
    if (y_offset < 0) y_offset = 0;
    Serial.printf("Successfully opened GIF; Canvas size = %d x %d\n", gif.getCanvasWidth(), gif.getCanvasHeight());
    Serial.flush();
    while (gif.playFrame(true, NULL))
    {      
      if ( (millis() - start_tick) > 8000) { // we'll get bored after about 8 seconds of the same looping gif
        break;
      }
    }
    gif.close();
  }

} /* ShowGIF() */

void setupGIF(){

  
  HUB75_I2S_CFG mxconfig(
    PANEL_RES_X,   // module width
    PANEL_RES_Y,   // module height
    PANEL_CHAIN    // Chain length
  );

    mxconfig.gpio.a = A_PIN;
    mxconfig.gpio.b = B_PIN;
    mxconfig.gpio.c = C_PIN;
    mxconfig.gpio.e = E_PIN;    
    mxconfig.clkphase = false;

  //mxconfig.driver = HUB75_I2S_CFG::FM6126A;

  // Display Setup
  dma_display = new MatrixPanel_I2S_DMA(mxconfig);
  dma_display->begin();
  dma_display->setBrightness8(128); //0-255
  dma_display->clearScreen();
  dma_display->fillScreen(myWHITE);

  Serial.println("Starting AnimatedGIFs Sketch");

  // Start filesystem
  Serial.println(" * Loading SPIFFS");
  if(!SPIFFS.begin()){
        Serial.println("SPIFFS Mount Failed");
  }
  
  dma_display->begin();
  
  /* all other pixel drawing functions can only be called after .begin() */
  dma_display->fillScreen(dma_display->color565(0, 0, 0));
  gif.begin(LITTLE_ENDIAN_PIXELS);

}

String gifDir = "/"; // play all GIFs in this directory on the SD card
char filePath[256] = { 0 };
File root, gifFile;


void loop() 
{
   while (1) // run forever
   {
      
      root = FILESYSTEM.open(gifDir);
      if (root)
      {
           gifFile = root.openNextFile();
            while (gifFile)
            {
              if (!gifFile.isDirectory()) // play it
              {
                
                // C-strings... urghh...                
                memset(filePath, 0x0, sizeof(filePath));                
                strcpy(filePath, gifFile.path());
                
                // Show it.
                ShowGIF(filePath);
               
              }
              gifFile.close();
              gifFile = root.openNextFile();
            }
         root.close();
      } // root
      
      delay(1000); // pause before restarting
      
   } // while
}







Combine the HTTP server and RGB matrix in the same code is not a good idea, because the HUB75 matrix require update hundreds times per second...

I know but I have no choice because I'm in trouble, I tried to get it to do serial communication between 2 esp32 but I didn't succeed. Any idea how to achieve that?

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