summaryrefslogtreecommitdiff
path: root/libraries/ESP_Async_WebServer/examples/PartitionDownloader/PartitionDownloader.ino
blob: 3c76366a9ec9de331d44cb1bc968ee5f0745168f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 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