131 lines
3.9 KiB
C++
131 lines
3.9 KiB
C++
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
|
|
|
|
//
|
|
// - Download ESP32 partition by name and/or type and/or subtype
|
|
// - Support encrypted and non-encrypted partitions
|
|
//
|
|
|
|
#include <Arduino.h>
|
|
#ifdef ESP32
|
|
#include <AsyncTCP.h>
|
|
#include <WiFi.h>
|
|
#elif defined(ESP8266)
|
|
#include <ESP8266WiFi.h>
|
|
#include <ESPAsyncTCP.h>
|
|
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
|
|
#include <RPAsyncTCP.h>
|
|
#include <WiFi.h>
|
|
#endif
|
|
|
|
#include <ESPAsyncWebServer.h>
|
|
#include <LittleFS.h>
|
|
|
|
#ifndef ESP32
|
|
// this example is only for the ESP32
|
|
void setup() {}
|
|
void loop() {}
|
|
#else
|
|
|
|
#include <esp_partition.h>
|
|
|
|
static AsyncWebServer server(80);
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
|
|
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
|
WiFi.mode(WIFI_AP);
|
|
WiFi.softAP("esp-captive");
|
|
#endif
|
|
|
|
LittleFS.begin(true);
|
|
|
|
// To upload the FS partition, run:
|
|
// > pio run -e arduino-3 -t buildfs
|
|
// > pio run -e arduino-3 -t uploadfs
|
|
//
|
|
// Examples:
|
|
//
|
|
// - Download the partition named "spiffs": http://192.168.4.1/partition?label=spiffs
|
|
// - Download the partition named "spiffs" with type "data": http://192.168.4.1/partition?label=spiffs&type=1
|
|
// - Download the partition named "spiffs" with type "data" and subtype "spiffs": http://192.168.4.1/partition?label=spiffs&type=1&subtype=130
|
|
// - Download the partition with subtype "nvs": http://192.168.4.1/partition?type=1&subtype=2
|
|
//
|
|
// "type" and "subtype" IDs can be found in esp_partition.h header file.
|
|
//
|
|
// Add "&raw=false" parameter to download the partition unencrypted (for encrypted partitions).
|
|
// By default, the raw partition is downloaded, so if a partition is encrypted, the encrypted data will be downloaded.
|
|
//
|
|
// To browse a downloaded LittleFS partition, you can use https://tniessen.github.io/littlefs-disk-img-viewer/ (block size is 4096)
|
|
//
|
|
server.on("/partition", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
const AsyncWebParameter *pLabel = request->getParam("label");
|
|
const AsyncWebParameter *pType = request->getParam("type");
|
|
const AsyncWebParameter *pSubtype = request->getParam("subtype");
|
|
const AsyncWebParameter *pRaw = request->getParam("raw");
|
|
|
|
if (!pLabel && !pType && !pSubtype) {
|
|
request->send(400, "text/plain", "Bad request: missing parameter");
|
|
return;
|
|
}
|
|
|
|
esp_partition_type_t type = ESP_PARTITION_TYPE_ANY;
|
|
esp_partition_subtype_t subtype = ESP_PARTITION_SUBTYPE_ANY;
|
|
const char *label = nullptr;
|
|
bool raw = true;
|
|
|
|
if (pLabel) {
|
|
label = pLabel->value().c_str();
|
|
}
|
|
|
|
if (pType) {
|
|
type = (esp_partition_type_t)pType->value().toInt();
|
|
}
|
|
|
|
if (pSubtype) {
|
|
subtype = (esp_partition_subtype_t)pSubtype->value().toInt();
|
|
}
|
|
|
|
if (pRaw && pRaw->value() == "false") {
|
|
raw = false;
|
|
}
|
|
|
|
const esp_partition_t *partition = esp_partition_find_first(type, subtype, label);
|
|
|
|
if (!partition) {
|
|
request->send(404, "text/plain", "Partition not found");
|
|
return;
|
|
}
|
|
|
|
AsyncWebServerResponse *response =
|
|
request->beginChunkedResponse("application/octet-stream", [partition, raw](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
|
|
const size_t remaining = partition->size - index;
|
|
if (!remaining) {
|
|
return 0;
|
|
}
|
|
const size_t len = std::min(maxLen, remaining);
|
|
if (raw && esp_partition_read_raw(partition, index, buffer, len) == ESP_OK) {
|
|
return len;
|
|
}
|
|
if (!raw && esp_partition_read(partition, index, buffer, len) == ESP_OK) {
|
|
return len;
|
|
}
|
|
return 0;
|
|
});
|
|
|
|
response->addHeader("Content-Disposition", "attachment; filename=" + String(partition->label) + ".bin");
|
|
response->setContentLength(partition->size);
|
|
|
|
request->send(response);
|
|
});
|
|
|
|
server.begin();
|
|
}
|
|
|
|
void loop() {
|
|
delay(100);
|
|
}
|
|
|
|
#endif
|