ESP32 SD_MMCでブラウザ上にSDカードの内容を表示

SD.hを使用してブラウザに表示する参考ソフト先人の方が公開されておりましたが
SD_MMC版のブラウザ表示ソフトはどこにも見当たらなかったので、先人の皆様のソフトを参考に作成しました。

最初に、Wi-Fiの設定プログラムです。

//Wi-Fiの設定は、ESP-Touchから行うこと

#include "WiFi.h"
WiFiServer server(80);//portの指定

//Wi-FIの初期設定
void WiFiInit(){

  // 前回接続時情報で接続する
  Serial.println("WiFi begin");
  WiFi.begin();
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
    // 10秒以上接続できなかったら抜ける
    if ( 10000 < millis() ) {
      break;
    }
  }
  Serial.println("");
  // 未接続の場合にはSmartConfig待受
  if ( WiFi.status() != WL_CONNECTED ) {
    WiFi.mode(WIFI_STA);
    WiFi.beginSmartConfig();
    Serial.println("Waiting for SmartConfig");
    while (!WiFi.smartConfigDone()) {
      delay(500);
      Serial.print("#");
      // 30秒以上接続できなかったら抜ける
      if ( 30000 < millis() ) {
        Serial.println("");
        Serial.println("Reset");
        ESP.restart();
      }
    }
    // Wi-fi接続
    Serial.println("");
    Serial.println("Waiting for WiFi");
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
      // 60秒以上接続できなかったら抜ける
      if ( 60000 < millis() ) {
        Serial.println("");
        Serial.println("Reset");
        ESP.restart();
      }
    }
    Serial.println("");
    Serial.println("WiFi Connected.");
  }
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

}

次はSDカードの初期化プログラムです。

//--------------SD定義
#include "sd_read_write.h"
#include "SD_MMC.h"
//ESP32 WRover-eの場合のピンアサインです。
#define SD_MMC_CMD 15 //Please do not modify it.
#define SD_MMC_CLK 14 //Please do not modify it. 
#define SD_MMC_D0  2  //Please do not modify it.

//ESP32S3 WROOMなら
#define SD_MMC_CMD 38  //Please do not modify it.
#define SD_MMC_CLK 39  //Please do not modify it.
#define SD_MMC_D0 40   //Please do not modify it.

//----------------

void SDInit(){

  SD_MMC.setPins(SD_MMC_CLK, SD_MMC_CMD, SD_MMC_D0);
    if (!SD_MMC.begin("/sdcard", true, true, SDMMC_FREQ_DEFAULT, 5)) {
      Serial.println("Card Mount Failed");
      return;
    }
    
    uint8_t cardType = SD_MMC.cardType();
    if(cardType == CARD_NONE){
        Serial.println("No SD_MMC card attached");
        return;
    }

    Serial.print("SD_MMC Card Type: ");
    if(cardType == CARD_MMC){
        Serial.println("MMC");
    } else if(cardType == CARD_SD){
        Serial.println("SDSC");
    } else if(cardType == CARD_SDHC){
        Serial.println("SDHC");
    } else {
        Serial.println("UNKNOWN");
    }

    uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);
    Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize);
}

以下Libです。そのままコピペしてファイルを作ってください。
SDカードの初期化のためのライブラリ

#ifndef __SD_READ_WRITE_H
#define __SD_READ_WRITE_H

#include "Arduino.h"
#include "FS.h"


void listDir(fs::FS &fs, const char * dirname, uint8_t levels);
void createDir(fs::FS &fs, const char * path);
void removeDir(fs::FS &fs, const char * path);
void readFile(fs::FS &fs, const char * path);
void writeFile(fs::FS &fs, const char * path, const char * message);
void appendFile(fs::FS &fs, const char * path, const char * message);
void renameFile(fs::FS &fs, const char * path1, const char * path2);
void deleteFile(fs::FS &fs, const char * path);
void testFileIO(fs::FS &fs, const char * path);

#endif
#include "sd_read_write.h"

void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
    Serial.printf("Listing directory: %s\n", dirname);

    File root = fs.open(dirname);
    if(!root){
        Serial.println("Failed to open directory");
        return;
    }
    if(!root.isDirectory()){
        Serial.println("Not a directory");
        return;
    }

    File file = root.openNextFile();
    while(file){
        if(file.isDirectory()){
            Serial.print("  DIR : ");
            Serial.println(file.name());
            if(levels){
                listDir(fs, file.path(), levels -1);
            }
        } else {
            Serial.print("  FILE: ");
            Serial.print(file.name());
            Serial.print("  SIZE: ");
            Serial.println(file.size());
        }
        file = root.openNextFile();
    }
}

void createDir(fs::FS &fs, const char * path){
    Serial.printf("Creating Dir: %s\n", path);
    if(fs.mkdir(path)){
        Serial.println("Dir created");
    } else {
        Serial.println("mkdir failed");
    }
}

void removeDir(fs::FS &fs, const char * path){
    Serial.printf("Removing Dir: %s\n", path);
    if(fs.rmdir(path)){
        Serial.println("Dir removed");
    } else {
        Serial.println("rmdir failed");
    }
}

void readFile(fs::FS &fs, const char * path){
    Serial.printf("Reading file: %s\n", path);

    File file = fs.open(path);
    if(!file){
        Serial.println("Failed to open file for reading");
        return;
    }

    Serial.print("Read from file: ");
    while(file.available()){
        Serial.write(file.read());
    }
}

void writeFile(fs::FS &fs, const char * path, const char * message){
    Serial.printf("Writing file: %s\n", path);

    File file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Failed to open file for writing");
        return;
    }
    if(file.print(message)){
        Serial.println("File written");
    } else {
        Serial.println("Write failed");
    }
}

void appendFile(fs::FS &fs, const char * path, const char * message){
    Serial.printf("Appending to file: %s\n", path);

    File file = fs.open(path, FILE_APPEND);
    if(!file){
        Serial.println("Failed to open file for appending");
        return;
    }
    if(file.print(message)){
        Serial.println("Message appended");
    } else {
        Serial.println("Append failed");
    }
}

void renameFile(fs::FS &fs, const char * path1, const char * path2){
    Serial.printf("Renaming file %s to %s\n", path1, path2);
    if (fs.rename(path1, path2)) {
        Serial.println("File renamed");
    } else {
        Serial.println("Rename failed");
    }
}

void deleteFile(fs::FS &fs, const char * path){
    Serial.printf("Deleting file: %s\n", path);
    if(fs.remove(path)){
        Serial.println("File deleted");
    } else {
        Serial.println("Delete failed");
    }
}

void testFileIO(fs::FS &fs, const char * path){
    File file = fs.open(path);
    static uint8_t buf[512];
    size_t len = 0;
    uint32_t start = millis();
    uint32_t end = start;
    if(file){
        len = file.size();
        size_t flen = len;
        start = millis();
        while(len){
            size_t toRead = len;
            if(toRead > 512){
                toRead = 512;
            }
            file.read(buf, toRead);
            len -= toRead;
        }
        end = millis() - start;
        Serial.printf("%u bytes read for %u ms\r\n", flen, end);
        file.close();
    } else {
        Serial.println("Failed to open file for reading");
    }

    file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Failed to open file for writing");
        return;
    }

    size_t i;
    start = millis();
    for(i=0; i<2048; i++){
        file.write(buf, 512);
    }
    end = millis() - start;
    Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
    file.close();
}

HTML表示用のライブラリ

#ifndef CHECHANDRESPONSE_H
#define CHECHANDRESPONSE_H

//you could chose readwrite\readonly
#define readrite

//you could chose UseWiFi/UseEthernet
#define UseWiFi

//Enable/Disable Rename
#define EnableRename


#ifdef UseWiFi
  #include <WiFi.h>
  #define WiFiEthernet WiFi
  #define WiFiEthernetClient WiFiClient
#else
  #include <Ethernet.h>
  #define WiFiEthernet Ethernet
  #define WiFiEthernetClient EthernetClient
#endif

//ヘッダーの追加
#include "SD_MMC.h"

//もともとあったSD,SPIは使用しないので削除
//#include <SD.h>
//#include <SPI.h>

bool CheckAndResponse(WiFiEthernetClient &client);


void process_request(WiFiEthernetClient& client, String request);

void sendHTTP(WiFiEthernetClient& client, const String& request);
/*
bool checkfilename(String checkstr);

String kmgt(unsigned long bytes);

String getType(const String& extension);

String getFilename(const String& filename);

String getExtension(const String& filename);

String ipToString(uint32_t ip);

String processReequest(char c);

String urlEncode(String str);

String urlDecode(String str);
*/

#endif
//元々のソースではSD.hを使用していたが、今回はSDMMC.hでのSDカードの参照なので、SDの部分を全て
//SD_MMCに書き換えた

#include "CheckAndResponse.h"

// decode %URL
String urlDecode(String str) {
  String decoded = "";
  char temp[] = "0x00";
  int str_len = str.length();

  for (int i = 0; i < str_len; i++) {
    if (str[i] == '%') {
      if (i + 2 < str_len) {
        temp[2] = str[i + 1];
        temp[3] = str[i + 2];
        decoded += (char)strtol(temp, NULL, 16);
        i += 2;
      }
    } else if (str[i] == '+') {
      decoded += ' ';
    } else {
      decoded += str[i];
    }
  }
  return decoded;
}

// ecode %URL
String urlEncode(String str) {
  String encoded = "";
  char temp[] = "0x00";

  for (int i = 0; i < str.length(); i++) {
    char c = str[i];

    if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || c == '/') {
      encoded += c;
      //} else if (c == ' ') {
      //  encoded += '+';
    } else {
      sprintf(temp, "%02X", c);
      encoded += '%' + String(temp);
    }
  }
  return encoded;
}

//defines for client
#define BUFFLEN 256        //length of the receive buffer
char buff[BUFFLEN];        //buffer
int count = 0;             //counter for the buffer
bool isBlankLine = false;  //if the last line is empty, the end of request
String path;

bool POSTflag = false;
#ifndef readonly
String cmdfilename;
String newfilename;
int ContentLength;
String errormessage;
bool Uploadflag = false;
String boundary;
bool Header = true;  //when it is false, countdown ContentLength
#endif

#ifndef readonly
//put received char in buffer and check the GET command and empty line
String processReequest(char c) {
  if (c == '\r') {
    isBlankLine = false;
    return "";                       //if the code is CR, ignore it
  } else if (c == '\n') {            //if the code is NL, read the GET request
    buff[count] = '\0';              //put null character at the end
    String request = buff;           //convert to String
    if (!POSTflag && !Uploadflag) {  //nomarl Header
      isBlankLine = (count == 0);    //and check if the line is empty
    } else if (Uploadflag && Header) {
      Header = !(count == 0);
    } else if (!Header) {
      ContentLength -= count;  //count down ContenLength
    }
    //else if(!POSTflag && Uploadflag && count == 0){ //end header when fileupload
    //  isBlankLine = (count == 0);
    //}
    count = 0;
    return request;
  } else {  //if the code is not control code, record it
    isBlankLine = false;
    if (count >= (BUFFLEN - 1)) count = 0;      //if almost overflow, reset the counter
    buff[count++] = c;                          //add char at the end of buffer
    if (count == ContentLength && POSTflag) {   //POST Payload finished
      buff[count] = '\0';                       //put null character at the end
      String request = buff;                    //convert to String
      if (request.startsWith("cmdfilename")) {  //finish post payload
        Serial.println("POST is finished");
        isBlankLine = true;
        count = 0;
        return request;
      }
    }
    return "";
  }
}
#else
String processReequest(char c) {
  if(c == '\r'){ //if the code is CR, ignore it
    isBlankLine = false;
    return "";
  }
  else if(c == '\n') {  //if the code is NL, read the GET request
    buff[count]='\0'; //put null character at the end
    String request = buff; //convert to String
    isBlankLine = (count == 0); //and check if the line is empty
    count=0;
    return request;
  }
  else { //if the code is not control code, record it
    isBlankLine = false;
    if(count >= (BUFFLEN - 1) ) count=0; //if almost overflow, reset the counter
      buff[count++]=c; //add char at the end of buffer
    return "";
  }
}
#endif

// https://qiita.com/dojyorin/items/ac56a1c2c620782d90a6
String ipToString(uint32_t ip) {
  String result = "";
  result += String((ip & 0xFF), 10);
  result += ".";
  result += String((ip & 0xFF00) >> 8, 10);
  result += ".";
  result += String((ip & 0xFF0000) >> 16, 10);
  result += ".";
  result += String((ip & 0xFF000000) >> 24, 10);
  return result;
}

String getExtension(const String& filename) {
  int dotIndex = filename.lastIndexOf('.');
  if (dotIndex == -1 || dotIndex == filename.length() - 1) {
    return "";
  }
  return filename.substring(dotIndex + 1);
}

String getFilename(const String& filename) {
  int dotIndex = filename.lastIndexOf('/');
  if (dotIndex == -1 || dotIndex == filename.length() - 1) {
    return "";
  }
  return filename.substring(dotIndex + 1);
}

//decide header by extension
String getType(const String& extension) {
  if (extension.equalsIgnoreCase("txt")) {
    return "text/plain";
  } else if (extension.equalsIgnoreCase("csv")) {
    return "text/csv";
  } else if (extension.equalsIgnoreCase("html") || extension.equalsIgnoreCase("htm")) {
    return "text/html";
  } else if (extension.equalsIgnoreCase("css")) {
    return "text/css";
  } else if (extension.equalsIgnoreCase("js")) {
    return "text/javascript";
  } else if (extension.equalsIgnoreCase("json")) {
    return "application/json";
  } else if (extension.equalsIgnoreCase("pdf")) {
    return "application/pdf";
  } else if (extension.equalsIgnoreCase("jpg") || extension.equalsIgnoreCase("jpeg")) {
    return "image/jpeg";
  } else if (extension.equalsIgnoreCase("png")) {
    return "image/png";
  } else if (extension.equalsIgnoreCase("gif")) {
    return "image/gif";
  } else if (extension.equalsIgnoreCase("svg")) {
    return "image/svg+xml";
  } else if (extension.equalsIgnoreCase("zip")) {
    return "application/zip";
  } else if (extension.equalsIgnoreCase("mpeg") || extension.equalsIgnoreCase("mpg")) {
    return "video/mpeg";
  } else {
    return "other";
  }
}

String kmgt(unsigned long bytes) {
  if (bytes < 1000) {
    return String(bytes) + "B";
  } else if (1000 <= bytes && bytes < 1000000) {
    return String(int(bytes / 1000)) + "KB";
  } else if (1000000 <= bytes && bytes < 1000000000) {
    return String(int(bytes / 1000000)) + "MB";
  } else{
    return String(int(bytes / 1000000000)) + "GB";
  }
}

#ifndef readonly
//check not use Forbidden characters
bool checkfilename(String checkstr) {                                                   //OK > true, invalid > false
  if (checkstr.indexOf("/") == checkstr.length() - 1 || checkstr.indexOf("/") == -1) {  //If "/" is used as the last character
    return checkstr.indexOf("\\") == -1 && checkstr.indexOf(":") == -1 && checkstr.indexOf("*") == -1 && checkstr.indexOf("?") == -1 && checkstr.indexOf("\"") == -1 && checkstr.indexOf("<") == -1 && checkstr.indexOf(">") == -1 && checkstr.indexOf("|") == -1;
  }
  return false;
}
#endif

bool CheckAndResponse(WiFiEthernetClient &client){
  if (client) {
    Serial.println("new client");
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        //Serial.write(c); //Output Request from client
        String request = processReequest(c);
        if (!request.equals("")) {
          process_request(client, request);
        }
        //if the line is blank, the request has ended.
        if (isBlankLine) {
          sendHTTP(client, request);  //send HTTP response
          break;
        }
      }
    }
    return true;
  }
  return false;
}

#ifndef readonly
void process_request(WiFiEthernetClient& client, String request) {
  if (request.startsWith("GET")) {
    //String path = request.substring(4).toInt();
    path = request;
    path.replace("GET ", "");
    path.replace(" HTTP/1.1", "");
    path = urlDecode(path);  //decode%
    POSTflag = false;
    Uploadflag = false;
  } else if (request.startsWith("POST")) {
    Serial.print("post:");
    Serial.println(request);
    path = request;
    path.replace("POST ", "");
    path.replace(" HTTP/1.1", "");
    path = urlDecode(path);  //decode%
    POSTflag = true;
    Uploadflag = false;
  } else if (request.startsWith("Content-Length") && POSTflag) {
    //Serial.print("Content-Length:");
    //Serial.println(request);
    request.replace("Content-Length: ", "");
    ContentLength = request.toInt();
    //Serial.print("ContentLength=");
    //Serial.println(ContentLength);
  } else if (request.startsWith("cmdfilename") && POSTflag) {
    //Serial.print("cmd:");
    //Serial.println(request);
    cmdfilename = request.substring(0, request.indexOf("&"));
    cmdfilename.replace("cmdfilename=", "");
    String secondIndex = request.substring(request.indexOf("&") + 1, request.lastIndexOf("&"));
    String thirdIndex = request.substring(request.lastIndexOf("&") + 1, request.length());
    if (secondIndex.startsWith("newfilename")) {
      newfilename = secondIndex;
    } else {
      newfilename = thirdIndex;
    }
    newfilename.replace("newfilename=", "");
    cmdfilename = urlDecode(cmdfilename);                              //decode
    newfilename = urlDecode(newfilename);                              //decode
    if (!checkfilename(cmdfilename) || !checkfilename(newfilename)) {  //OK > true, invalid > false
      POSTflag = false;
      errormessage = "Invalid characters are used.";
    } else if (cmdfilename.equals("")) {
      POSTflag = false;
      errormessage = "Prease enter file name to operate.";
    }
    //Serial.print("cmdfilename:");
    //Serial.println(cmdfilename);
    //Serial.print("newfilename:");
    //Serial.println(newfilename);
  } else if (request.startsWith("Content-Type") && POSTflag) {
    if (!Uploadflag) {  //serch boundary
      //serch "boundary="
      while (!request.startsWith("boundary=")) {
        request.remove(0, 1);  //remove first letter
        if (request.length() == 0) {
          break;
        }
      }
      if (request.length() != 0) {  //if boundary found
        request.replace("boundary=", "");
        boundary = request;
        //Serial.print("boundary=");
        //Serial.println(boundary);
        Uploadflag = true;
      } else {  //if boundary didn't find
        Uploadflag = false;
      }
    } else {  //upload file
      //ContentLength -= (request.length() + 1);
      String filename = path + request;
      //setting upload file
      newfilename = path + newfilename;
      File file = SD_MMC.open(newfilename, FILE_WRITE);
      while (client.available()) {
        char c = client.read();
        //Serial.write(c);
        ContentLength -= 1;
        //Serial.println(ContentLength);
        if (c == '\n') {
          break;
        }
      }
      //write file
      Serial.println("Start writting uploadfile");
      //recive file with buffer
      const int BufferSize = 1024;
      //int finish_count = BufferSize + boundary.length() + 3 + 11; //use client check
      int finish_count = boundary.length() + 3 + 11;  //use client check
      //const int filesize = ContentLength - boundary.length() - 3 - 11; //use file check
      const size_t bufferSize = BufferSize;  //buffer size
      byte buffe[bufferSize];                //buffe
      int countb = 0;
      const int misslimit = 2048;
      int misscount = 0;

      while (ContentLength > finish_count && misscount < misslimit) {
        while (countb < BufferSize && ContentLength > finish_count) {
          if (client.available()) {
            buffe[countb] = client.read();
            countb += 1;
            ContentLength -= 1;
          } else {
            //Serial.print(".");
            misscount += 1;
            delay(10);
            break;
          }
        }
        //Serial.println(ContentLength);
        file.write(buffe, countb);
        countb = 0;
      }
      while (client.available() && misscount < misslimit) {  //write last boudary
        char c = client.read();
        Serial.write(c);
      }
      file.close();
      Uploadflag = false;
      POSTflag = false;
      Header = true;

      if (!(misscount < misslimit)) {
        Serial.println("To many packet loss.");
        client.println("HTTP/1.1 500 Internal Server Error");
        client.println("Connection: close");
        errormessage = "File will be broken. Delete & try again.";
        isBlankLine = false;
      } else {
        isBlankLine = true;
      }
    }
  } else if (request.endsWith(boundary) && Uploadflag) {  //start payload
    //Serial.println("payload start");
    Serial.println(request);
    //ContentLength -= (boundary.length()+3); //boundary,--,\n
  } else if (request.startsWith("Content-Disposition") && Uploadflag) {  //get upload filename
    //ContentLength -= (request.length() + 1);
    //serch filename=
    while (!request.startsWith("filename=")) {
      request.remove(0, 1);  //remove first letter
      if (request.length() == 0) {
        errormessage = "Not found filename.";
      }
    }
    request.replace("filename=\"", "");
    request.replace("\"", "");
    newfilename = request;
    Serial.print("newfilename:");
    Serial.println(newfilename);
  }
}
#else
void process_request(WiFiEthernetClient &client,String request){
  if(request.startsWith("GET")){
    //String path = request.substring(4).toInt();
    path = request;
    path.replace("GET ","");
    path.replace(" HTTP/1.1","");
    path = urlDecode(path); //decode%
  }
}
#endif

void sendHTTP(WiFiEthernetClient& client, const String& request) {
  //Serial.println("");
  Serial.print("path:");
  Serial.println(path);
  if (path.equals("")) {
    path = "/";
  }
  if (path.endsWith("/") && !POSTflag) {  //readDirectory
    if (!path.equals("/")) {
      path.remove(path.length() - 1);  //delet last "/"
    }
    if (SD_MMC.exists(path)) {  //check path is exist
      client.println("HTTP/1.1 200 OK");
      client.println("Content-Type: text/html");
      client.println("Connection: close");
      client.println();
      client.println("");
      client.println("");
      Serial.print("Directroy:");
      Serial.println(path);
      client.println("<!DOCTYPE html>");
      client.println("<html>");
      client.println("<head>");
      client.println("<title>SD Reader</title>");
      client.println("<meta charset=\"UTF-8\">");
      client.println("</head>");
      client.println("<body>");
      //display current path
      client.print("<h1>");
      client.print(path);
      if (!path.equals("/")) {  //add "/"
        client.print("/");
      }
      client.println("</h1>");

  #ifndef readonly
      //command
      client.print("<form action=\"");
      client.print(urlEncode(path));
      if (!path.equals("/")) {
        client.print("/");
      }
      client.println("\" method=\"POST\">");
      client.println("Enter File or Folder name to operate.<br>");
      client.println("<input type=\"text\" name=\"cmdfilename\">");
      client.println("<input type=\"submit\" name=\"mkdir\" value=\"mkdir\">");
      client.println("<input type=\"submit\" name=\"delete\" value=\"delete\"><br>");

  #ifndef DisableRename
      client.println("Enter new name.<br>");
      client.println("<input type=\"text\" name=\"newfilename\">");
      client.println("<input type=\"submit\" name=\"rename\" value=\"rename\">");
  #endif
      
      client.println("</form>");
      //file upload
      client.print("<form action=\"");
      client.print(urlEncode(path));
      if (!path.equals("/")) {
        client.print("/");
      }
      client.println("\" method=\"POST\" enctype=\"multipart/form-data\">");
      client.println("Upload file. (Recommend < 20MB)<br>");
      client.println("<input type=\"file\" name=\"uploadfile\">");
      client.println("<input type=\"submit\" value=\"upload\">");
      client.println("</form>");
      //display Error message
      if (!errormessage.equals("")) {
        client.print("<p><font color=\"red\">");
        client.println(errormessage);
        client.print("</font></p>");
        errormessage = "";
      }
  #endif

      //Parent Directory
      String IPaddr = ipToString(WiFiEthernet.localIP());
      if (!path.equals("/")) {
        client.print("<p><a href=\"");
        client.print("http://");
        client.print(IPaddr);
        client.print(urlEncode(path.substring(0, path.lastIndexOf("/") + 1)));  //Parent Directory path
        client.print("\" >");
        client.print("Parent Directory");
        client.print("</a>");
        client.println("</p>");
      }
      client.print("<hr>");
      //list up directory contents
      File dir = SD_MMC.open(path);
      while (true) {
        File entry = dir.openNextFile();
        if (!entry) {
          break;
        }
        String filename = entry.name();
        if (entry.isDirectory()) {
          filename += "/";
        }
        String fileurl = "http://" + IPaddr + urlEncode(path);
        if (path.equals("/")) {
          fileurl += urlEncode(filename);
        } else {
          fileurl += "/" + urlEncode(filename);
        }
        client.print("<p>");
        client.print("<a href=\"");
        client.print(fileurl);
        client.print("\" >");
        client.print(filename);
        client.println("</a>");
        if (!filename.endsWith("/")) {  //display file size
          client.print(" ");
          client.println(kmgt(entry.size()));
        }
        client.println("</p>");
        entry.close();
      }
      dir.close();
      client.print("<hr>");
      client.print("<p>");
      client.print("Powered by ");
      client.print("<a href=\"https://github.com/UnagiDojyou/ArduinoIDE_SD_FAT32_Fileserver\">ArduinoIDE_SD_FAT32_Fileserver</a>");
      client.println("</p>");
      client.println("</body>");
      client.println("</html>");
    } else {  //Directory not Found
      client.println("HTTP/1.1 404 Not Found");
      client.println("Connection: close");
    }
  } else if (!POSTflag) {  //File
    if (SD_MMC.exists(path)) {
      Serial.print("File:");
      Serial.println(path);
      String extension = getExtension(getFilename(path));
      File file = SD_MMC.open(path);
      unsigned long filesize = file.size();
      client.println("HTTP/1.1 200 OK");
      client.print("Content-Length: ");
      client.println(filesize);
      if (extension.equals("other")) {
        client.print("Content-Disposition");
      } else {
        client.print("Content-Type: ");
        client.println(getType(extension));
      }
      client.println("Connection: close");
      client.println();
      //send file to client with 1024 buffer.
      const size_t bufferSize = 1024;  //buffer size
      byte buffe[bufferSize];          //buffe
      while (file.available() && client.connected()) {
        size_t bytesRead = file.read(buffe, bufferSize);
        client.write(buffe, bytesRead);
      }
      file.close();
    } else {  //File not Found
      client.println("HTTP/1.1 404 Not Found");
      client.println("Connection: close");
    }
  }

  #ifndef readonly
  else if (POSTflag && request.indexOf("mkdir=mkdir") > -1) {  //mkdri
    //Serial.println("mkdir");
    String newdir = path + cmdfilename;
    Serial.print("mkdir:");
    Serial.println(newdir);
    if (!SD_MMC.mkdir(newdir)) {
      errormessage = "Cannot make " + newdir;
    }
  } else if (POSTflag && request.indexOf("delete=delete") > -1) {  //delete
    //Serial.println("delete");
    String rmpath = path + cmdfilename;
    Serial.print("delete:");
    Serial.println(rmpath);
    if (cmdfilename.endsWith("/")) {  //directory
      if (!SD_MMC.rmdir(rmpath.substring(0, rmpath.length() - 1))) {
        errormessage = "Cannot delete " + rmpath;
      }
    } else {  //file
      if (!SD_MMC.remove(rmpath)) {
        errormessage = "Cannot delete " + rmpath + "/";
      }
    }
  } 
  
  #ifndef DisableRename
  else if (POSTflag && request.indexOf("rename=rename") > -1) {  //rename
    Serial.println("rename");
    String Newname = path + newfilename;
    String Oldname = path + cmdfilename;
    if (Newname.endsWith("/") ^ Oldname.endsWith("/")) {
      errormessage = "Either \"/\" is missing or surplus.";
    } else if (!SD_MMC.rename(Oldname, Newname)) {
      errormessage = "Cannot rename " + Oldname + "to" + "Newname";
    }
  }
  #endif

  if (POSTflag) {  //send page(must be exexute if(path.endsWith("/") && !POSTflag))
    POSTflag = false;
    sendHTTP(client, request);
  }
  #endif

  client.println("");
  client.stop();
  Serial.println("Response finish");
  return;
}

以上がライブラリになります。
最後にこれらを組み合わせてプログラムを作成すると以下のようになります。

//2024 0524 ブラウザでSDカードの中身を参照可能なところまで作り込みOK
//URLの指定は、IPアドレス/フォルダ名/ とすること 最後の/を忘れないこと

//Wi-Fiの設定は、ESP-Touchから行うこと

#include <Arduino.h>

#include "WiFi.h"
WiFiServer server(80);

//--------------SD定義
#include "sd_read_write.h"
#include "SD_MMC.h"
#define SD_MMC_CMD 15 //Please do not modify it.
#define SD_MMC_CLK 14 //Please do not modify it. 
#define SD_MMC_D0  2  //Please do not modify it.
//----------------


#include <SD.h>
#include <FS.h>
#include "CheckAndResponse.h"//同じディレクトリに置けば認識される
//https://github.com/UnagiDojyou/ArduinoIDE_SD_FAT32_Fileserver/tree/main/ESP32_FAT32_Fileserver_readwrite


//Wi-FIの初期設定
void WiFiInit(){

  // 前回接続時情報で接続する
  Serial.println("WiFi begin");
  WiFi.begin();
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
    // 10秒以上接続できなかったら抜ける
    if ( 10000 < millis() ) {
      break;
    }
  }
  Serial.println("");
  // 未接続の場合にはSmartConfig待受
  if ( WiFi.status() != WL_CONNECTED ) {
    WiFi.mode(WIFI_STA);
    WiFi.beginSmartConfig();
    Serial.println("Waiting for SmartConfig");
    while (!WiFi.smartConfigDone()) {
      delay(500);
      Serial.print("#");
      // 30秒以上接続できなかったら抜ける
      if ( 30000 < millis() ) {
        Serial.println("");
        Serial.println("Reset");
        ESP.restart();
      }
    }
    // Wi-fi接続
    Serial.println("");
    Serial.println("Waiting for WiFi");
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
      // 60秒以上接続できなかったら抜ける
      if ( 60000 < millis() ) {
        Serial.println("");
        Serial.println("Reset");
        ESP.restart();
      }
    }
    Serial.println("");
    Serial.println("WiFi Connected.");
  }
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

}


void SDInit(){

  SD_MMC.setPins(SD_MMC_CLK, SD_MMC_CMD, SD_MMC_D0);
    if (!SD_MMC.begin("/sdcard", true, true, SDMMC_FREQ_DEFAULT, 5)) {
      Serial.println("Card Mount Failed");
      return;
    }
    
    uint8_t cardType = SD_MMC.cardType();
    if(cardType == CARD_NONE){
        Serial.println("No SD_MMC card attached");
        return;
    }

    Serial.print("SD_MMC Card Type: ");
    if(cardType == CARD_MMC){
        Serial.println("MMC");
    } else if(cardType == CARD_SD){
        Serial.println("SDSC");
    } else if(cardType == CARD_SDHC){
        Serial.println("SDHC");
    } else {
        Serial.println("UNKNOWN");
    }

    uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);
    Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize);
}


void setup() {
  // シリアル初期化
  Serial.begin(115200);
  WiFiInit();
  SDInit();
  server.begin(); //start the server
  Serial.print("\nHTTP server started at: ");
  Serial.println(WiFi.localIP());

  listDir(SD_MMC, "/", 0);

}

void loop() {
  WiFiClient client = server.available();
  CheckAndResponse(client);
}

SDカードの中身にmainというフォルダがあれば
http://192.168.24.15/main/ といったように指定します。
するとブラウザに表示されるはずです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする