update firmware v1.0.1

This commit is contained in:
yaozhenquan
2026-05-19 15:01:16 +08:00
parent 2b44d28149
commit 0b3d5ef60a
11 changed files with 329 additions and 95 deletions
+2
View File
@@ -2,6 +2,8 @@
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
set(PROJECT_VER "1.0.1")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
+1 -1
View File
@@ -689,7 +689,7 @@ static void app_task(void* param)
// ---- Startup ----
esp_err_t app_manager_start()
{
ESP_LOGI(g_tag, "Software version: V%u", APP_SW_VERSION);
ESP_LOGI(g_tag, "Software version: V%s", APP_SW_VERSION);
// ── First boot guide image ──
nvs_handle_t h;
+1 -1
View File
@@ -21,7 +21,7 @@
#define WIFI_AP_AUTO_OFF_TIMEOUT_MIN (10)
/** @brief Current application software version. */
#define APP_SW_VERSION (0x01)
#define APP_SW_VERSION "1.0.1"
/**
* @brief Displays the boot guide image.
+3 -2
View File
@@ -54,7 +54,7 @@ extern const char _binary_index_html_end[] asm("_binary_index_html_end");
#define SCAN_TIMEOUT_MS (8000)
#define CONNECT_TIMEOUT_MS (15000)
#define UPLOAD_MAX_SIZE (512 * 1024)
#define UPLOAD_MAX_SIZE (2 * 1024 * 1024)
#define PHOTOS_PER_PAGE (16)
#define MAX_PHOTOS (500)
@@ -138,7 +138,8 @@ static bool url_encode_component(const char *src, char *dst, size_t dst_sz)
for (size_t i = 0; src[i]; i++) {
unsigned char c = (unsigned char)src[i];
bool safe = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' ||
bool safe = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' ||
c == '_' || c == '.' || c == '~';
if (safe) {
+88 -32
View File
@@ -1592,6 +1592,10 @@ let modeList = [];
let confirmCallback = null;
let photoPage = 1;
let photoTotalPages = 1;
let photoPageCache = {}; // { [page]: { total_pages, names: [...] } }
let photoCache = {}; // { [name]: { name, url } }
let photoTotal = 0;
let photoPageLoading = false;
// ==================== API Helper ====================
async function apiCall(method, url, body, isFormData) {
@@ -1600,15 +1604,23 @@ async function apiCall(method, url, body, isFormData) {
opts.body = isFormData ? body : JSON.stringify(body);
if (!isFormData) opts.headers = { "Content-Type": "application/json" };
}
let res;
try {
const res = await fetch(url, opts);
const data = await res.json();
if (!res.ok) throw new Error(data.message || `HTTP ${res.status}`);
return data;
res = await fetch(url, opts);
} catch (e) {
if (e.message && !e.message.startsWith("HTTP")) throw e;
throw e;
}
let data = null;
try {
data = await res.json();
} catch (e) {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
throw new Error("Network request failed");
}
if (!res.ok) throw new Error(data.message || `HTTP ${res.status}`);
return data;
}
// ==================== Toast ====================
@@ -2654,11 +2666,6 @@ function applyModeConfig() {
requestAnimationFrame(() => {
rerenderCompositionLayout(false);
});
if (currentMode === "mode_1") {
photoPage = 1;
loadPhotoList(photoPage);
}
}
// ==================== Unified Settings Modal ====================
@@ -3271,10 +3278,17 @@ async function uploadOnly() {
formData.append("action", "upload_only");
formData.append("algorithm", displayMode);
showToast("Uploading...", "");
await apiCall("POST", "/api/photos/upload", formData, true);
const resp = await apiCall("POST", "/api/photos/upload", formData, true);
showToast("Uploaded successfully", "success");
photoPage = 9999;
loadPhotoList(photoPage);
if (displayMode === "nearest" && resp && resp.name) {
// Nearest photo inserts at front — all page boundaries shift, clear page cache
photoPageCache = {};
const m = resp.name.match(/^imageN0*(\d+)/i);
if (m) photoPage = Math.ceil(Number(m[1]) / getPhotoPerPage());
} else {
photoPage = 9999;
}
await loadPhotoList(photoPage, /* forceRefresh */ true);
loadStorage();
} catch(e) { showToast(e.message, "error"); }
}
@@ -3300,10 +3314,18 @@ async function uploadWithDisplay() {
formData.append("algorithm", displayMode);
showToast("Uploading...", "");
await apiCall("POST", "/api/photos/upload", formData, true);
const resp = await apiCall("POST", "/api/photos/upload", formData, true);
showToast("Uploaded & display updated", "success");
photoPage = 9999;
loadPhotoList(photoPage);
// Compute which page the new photo landed on from its name
if (displayMode === "nearest" && resp && resp.name) {
// Nearest photo inserts at front — all pages shift, clear page cache
photoPageCache = {};
const m = resp.name.match(/^imageN0*(\d+)/i);
if (m) photoPage = Math.ceil(Number(m[1]) / getPhotoPerPage());
} else {
photoPage = 9999; // Dither appends at end, only last page changes
}
await loadPhotoList(photoPage, /* forceRefresh */ true);
loadStorage();
} catch(e) { showToast(e.message, "error"); }
}
@@ -3315,20 +3337,43 @@ function getPhotoPerPage() {
return 12;
}
async function loadPhotoList(page) {
async function loadPhotoList(page, forceRefresh = false) {
page = page || photoPage;
const perPage = getPhotoPerPage();
// Serve from cache if this page was loaded before
if (!forceRefresh && photoPageCache[page]) {
photoPage = page;
renderPhotoGridFromNames(photoPageCache[page]);
renderPagination();
return;
}
photoPageLoading = true;
try {
const data = await apiCall("GET", `/api/photos/list?page=${page}&per_page=${perPage}`);
photoPage = data.page;
photoTotalPages = data.total_pages;
renderPhotoGrid(data.photos, data.total);
renderPagination();
if (data.page === page || page === photoPage) {
// Store per-photo data globally
const names = [];
data.photos.forEach(p => {
photoCache[p.name] = { name: p.name, url: p.url };
names.push(p.name);
});
photoPageCache[data.page] = names;
photoPage = data.page;
photoTotalPages = data.total_pages;
photoTotal = data.total;
renderPhotoGridFromNames(names);
renderPagination();
}
} catch(e) { /* silent */ }
photoPageLoading = false;
}
function goPhotoPage(page) {
if (page < 1 || page > photoTotalPages) return;
photoPage = page;
renderPagination();
loadPhotoList(page);
}
@@ -3348,25 +3393,26 @@ function renderPagination() {
next.disabled = photoPage >= photoTotalPages;
}
function renderPhotoGrid(photos, total) {
function renderPhotoGridFromNames(names) {
const grid = document.getElementById("photo-grid");
const count = document.getElementById("photo-count");
count.textContent = total > 0 ? `(${total})` : "";
count.textContent = photoTotal > 0 ? `(${photoTotal})` : "";
if (photos.length === 0) {
if (names.length === 0) {
grid.innerHTML = `<div style="color:#999;font-size:14px;text-align:center;grid-column:1/-1;padding:20px;">No photos</div>`;
return;
}
grid.innerHTML = photos.map(p =>
`<div class="photo-card">
grid.innerHTML = names.map(name => {
const p = photoCache[name] || { name, url: "" };
return `<div class="photo-card">
<img class="thumb" src="${escapeHtml(p.url)}" alt="${escapeHtml(p.name)}" loading="lazy">
<div class="photo-info"><div class="photo-name" title="${escapeHtml(p.name)}">${escapeHtml(p.name)}</div></div>
<div class="photo-actions">
<button class="btn btn-outline btn-sm" onclick="displayPhoto('${escapeAttr(p.name)}')">View</button>
<button class="btn btn-danger btn-sm" onclick="deletePhoto('${escapeAttr(p.name)}')">Del</button>
</div>
</div>`
).join("");
</div>`;
}).join("");
}
function escapeAttr(s) { return s.replace(/'/g, "\\'").replace(/"/g, "&quot;"); }
@@ -3385,13 +3431,23 @@ function deletePhoto(name) {
await apiCall("DELETE", "/api/photos/delete?name=" + encodeURIComponent(name));
showToast("Deleted", "success");
loadStorage();
// 如果当前页删空则回退一页
if (photoPage > 1) {
// Remove only this photo from caches
delete photoCache[name];
photoTotal = Math.max(0, photoTotal - 1);
for (const key of Object.keys(photoPageCache)) {
photoPageCache[key] = photoPageCache[key].filter(n => n !== name);
}
// If the current page is now empty, step back
const names = photoPageCache[photoPage];
if (names && names.length === 0 && photoPage > 1) {
photoPage--;
} else if (!names && photoPage > 1) {
// Page not cached — check server whether it's now empty
const perPage = getPhotoPerPage();
const data = await apiCall("GET", `/api/photos/list?page=${photoPage}&per_page=${perPage}`);
if (data.photos.length === 0 && photoPage > 1) { photoPage--; }
if (data.photos.length === 0) { photoPage--; }
}
loadPhotoList(photoPage);
loadPhotoList(photoPage, /* forceRefresh */ true);
} catch(e) { showToast(e.message, "error"); }
});
}
@@ -22,9 +22,77 @@
static const char *TAG = "Slideshow";
// Define an invalid index to represent “no photo is currently displayed”
static constexpr uint8_t RX8130_RAM_INDEX_CURRENT_STORAGE = 0;
// Define an invalid index to represent "no photo is currently displayed"
#define NO_PHOTO 0xFFFF
namespace {
void resetPhotoIndexState(uint16_t &pending_index)
{
pending_index = NO_PHOTO;
hal.rx8130RamWrite(RX8130_RAM_INDEX_CURRENT_STORAGE, 0);
hal.rx8130RamWrite(RX8130_RAM_INDEX_CURRENT_STORAGE + 1, 0);
}
esp_err_t selectStorageMedia(bool sd_inserted, bool &sd_fallback_locked)
{
sd_fallback_locked = false;
if (sd_inserted) {
esp_err_t ret = hal_storage_init(APP_STORAGE_MEDIA_SDMMC);
if (ret == ESP_OK) {
return ESP_OK;
}
sd_fallback_locked = true;
ESP_LOGW(TAG, "SD init failed, fallback to SPI flash: %s", esp_err_to_name(ret));
}
return hal_storage_init(APP_STORAGE_MEDIA_SPIFLASH);
}
void ensureStorageMedia(bool sd_inserted, bool &last_sd_inserted, bool &sd_fallback_locked, uint16_t &pending_index)
{
if (!sd_inserted) {
last_sd_inserted = false;
sd_fallback_locked = false;
} else if (!last_sd_inserted) {
last_sd_inserted = true;
sd_fallback_locked = false;
}
hal_storage_media_t target_media =
(sd_inserted && !sd_fallback_locked) ? APP_STORAGE_MEDIA_SDMMC : APP_STORAGE_MEDIA_SPIFLASH;
if (hal_storage_get_media() == target_media) {
return;
}
esp_err_t ret = hal_storage_switch(target_media);
if (ret == ESP_OK) {
resetPhotoIndexState(pending_index);
return;
}
if (!sd_inserted) {
ESP_LOGW(TAG, "SPI flash switch failed: %s", esp_err_to_name(ret));
return;
}
sd_fallback_locked = true;
ESP_LOGW(TAG, "SD switch failed, fallback to SPI flash: %s", esp_err_to_name(ret));
if (hal_storage_get_media() != APP_STORAGE_MEDIA_SPIFLASH) {
esp_err_t fallback_ret = hal_storage_switch(APP_STORAGE_MEDIA_SPIFLASH);
if (fallback_ret != ESP_OK) {
ESP_LOGE(TAG, "SPI flash fallback switch failed: %s", esp_err_to_name(fallback_ret));
return;
}
}
resetPhotoIndexState(pending_index);
}
} // namespace
/* ---------- millis() ---------- */
static inline uint32_t millis_()
{
@@ -43,19 +111,15 @@ bool PhotoSlideshow::init(const char *dir_path, uint8_t interval_min)
_needs_refresh = false;
_last_btn_c = false;
_last_btn_b = false;
_last_sd_inserted = hal.isSDCardInserted();
_sd_fallback_locked = false;
_photo_list.clear();
_scr_w = hal.Canvas->width();
_scr_h = hal.Canvas->height();
M5.Speaker.setVolume(120);
if (hal.isSDCardInserted()) {
// Use the SD card at startup
hal_storage_init(APP_STORAGE_MEDIA_SDMMC);
} else {
// Use APP storage at startup
hal_storage_init(APP_STORAGE_MEDIA_SPIFLASH);
}
selectStorageMedia(_last_sd_inserted, _sd_fallback_locked);
scanPhotos();
hal.statusEventSend(OPERATION_EVENT_STARTUP_SUCCESS);
@@ -238,23 +302,7 @@ void PhotoSlideshow::update()
syncSettings();
// If an SD card is inserted and FLASH storage is currently in use, switch to the SD card
// If no SD card is inserted and SD storage is currently in use, switch to FLASH storage
if (hal.isSDCardInserted()) {
if (hal_storage_get_media() != APP_STORAGE_MEDIA_SDMMC) {
hal_storage_switch(APP_STORAGE_MEDIA_SDMMC);
_pending_index = NO_PHOTO;
hal.rx8130RamWrite(RX8130_RAM_INDEX_CURRENT, 0);
hal.rx8130RamWrite(RX8130_RAM_INDEX_CURRENT + 1, 0);
}
} else {
if (hal_storage_get_media() != APP_STORAGE_MEDIA_SPIFLASH) {
hal_storage_switch(APP_STORAGE_MEDIA_SPIFLASH);
_pending_index = NO_PHOTO;
hal.rx8130RamWrite(RX8130_RAM_INDEX_CURRENT, 0);
hal.rx8130RamWrite(RX8130_RAM_INDEX_CURRENT + 1, 0);
}
}
ensureStorageMedia(hal.isSDCardInserted(), _last_sd_inserted, _sd_fallback_locked, _pending_index);
// Check buttons
handleButtons();
@@ -158,6 +158,8 @@ private:
bool _last_btn_c = false;
bool _last_btn_b = false;
bool _last_btn_a = false;
bool _last_sd_inserted = false;
bool _sd_fallback_locked = false;
/* ---- Internal helpers ---- */
void syncSettings();
+2
View File
@@ -178,6 +178,8 @@ void Hal::init()
s_spi_bus_inited = true;
pm1.begin(&M5.In_I2C, M5PM1_DEFAULT_ADDR, M5PM1_I2C_FREQ_100K);
pm1.setI2cConfig(0);
pm1.pinMode(SD_DET_EN, OUTPUT);
pm1.digitalWrite(SD_DET_EN, HIGH);
pm1.pinMode(SD_DEC, INPUT_PULLUP);
pm1.pinMode(EPD_EN, OUTPUT);
pm1.digitalWrite(EPD_EN, HIGH);
+1
View File
@@ -134,6 +134,7 @@ private:
static void LedStatusIndicateTask(void* task_parameters);
static constexpr m5pm1_gpio_num_t SD_DEC = M5PM1_GPIO_NUM_1;
static constexpr m5pm1_gpio_num_t EPD_EN = M5PM1_GPIO_NUM_0;
static constexpr m5pm1_gpio_num_t SD_DET_EN = M5PM1_GPIO_NUM_4;
static constexpr gpio_num_t SYS_SCL_PIN = GPIO_NUM_2;
static constexpr gpio_num_t SYS_SDA_PIN = GPIO_NUM_3;
TaskHandle_t _led_status_indicate_task_handle = nullptr;
+134 -23
View File
@@ -158,9 +158,46 @@ static void usb_event_cb(tinyusb_event_t *event, void *arg)
}
}
static void _mount(void)
static esp_err_t install_tinyusb_device_driver(void)
{
ESP_ERROR_CHECK(tinyusb_msc_set_storage_mount_point(s_ctx.storage_hdl, TINYUSB_MSC_STORAGE_MOUNT_APP));
if (s_ctx.driver_installed) {
return ESP_OK;
}
tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG();
tusb_cfg.descriptor.device = &descriptor_config;
tusb_cfg.descriptor.full_speed_config = msc_fs_configuration_desc;
tusb_cfg.descriptor.string = string_desc_arr;
tusb_cfg.descriptor.string_count = sizeof(string_desc_arr) / sizeof(string_desc_arr[0]);
tusb_cfg.event_cb = usb_event_cb;
esp_err_t ret = tinyusb_driver_install(&tusb_cfg);
if (ret == ESP_OK) {
s_ctx.driver_installed = true;
}
return ret;
}
static esp_err_t uninstall_tinyusb_device_driver(void)
{
if (!s_ctx.driver_installed) {
return ESP_OK;
}
esp_err_t ret = tinyusb_driver_uninstall();
if (ret == ESP_OK) {
s_ctx.driver_installed = false;
}
return ret;
}
static esp_err_t _mount(void)
{
esp_err_t ret = tinyusb_msc_set_storage_mount_point(s_ctx.storage_hdl, TINYUSB_MSC_STORAGE_MOUNT_APP);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to switch storage mount point to APP: %s", esp_err_to_name(ret));
return ret;
}
ESP_LOGI(TAG, "ls %s:", BASE_PATH);
DIR *directory_handle = opendir(BASE_PATH);
@@ -168,16 +205,20 @@ static void _mount(void)
if (!directory_handle) {
if (errno == ENOENT) {
ESP_LOGE(TAG, "Directory doesn't exist %s", BASE_PATH);
ret = ESP_ERR_NOT_FOUND;
} else {
ESP_LOGE(TAG, "Unable to read directory %s", BASE_PATH);
ret = ESP_FAIL;
}
return;
tinyusb_msc_set_storage_mount_point(s_ctx.storage_hdl, TINYUSB_MSC_STORAGE_MOUNT_USB);
return ret;
}
struct dirent *entry;
while ((entry = readdir(directory_handle)) != NULL) {
printf(" %s\n", entry->d_name);
}
closedir(directory_handle);
return ESP_OK;
}
static esp_err_t storage_init_spiflash(wl_handle_t *wl_handle)
@@ -352,26 +393,37 @@ static esp_err_t _bringup(hal_storage_media_t media)
ESP_LOGE(TAG, "set_storage_callback fail: %s", esp_err_to_name(ret));
goto err_after_storage;
}
_mount();
{
tinyusb_config_t tusb_cfg = TINYUSB_DEFAULT_CONFIG();
tusb_cfg.descriptor.device = &descriptor_config;
tusb_cfg.descriptor.full_speed_config = msc_fs_configuration_desc;
tusb_cfg.descriptor.string = string_desc_arr;
tusb_cfg.descriptor.string_count = sizeof(string_desc_arr) / sizeof(string_desc_arr[0]);
tusb_cfg.event_cb = usb_event_cb;
ret = tinyusb_driver_install(&tusb_cfg);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "tinyusb_driver_install fail: %s", esp_err_to_name(ret));
goto err_after_storage;
}
s_ctx.driver_installed = true;
ret = _mount();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Storage mount to APP failed: %s", esp_err_to_name(ret));
goto err_after_storage;
}
ret = install_tinyusb_device_driver();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "tinyusb_driver_install fail: %s", esp_err_to_name(ret));
goto err_after_storage;
}
return ESP_OK;
err_after_storage:
uninstall_tinyusb_device_driver();
if (s_ctx.storage_hdl) {
tinyusb_msc_delete_storage(s_ctx.storage_hdl);
tinyusb_msc_mount_point_t cur;
if (tinyusb_msc_get_storage_mount_point(s_ctx.storage_hdl, &cur) == ESP_OK &&
cur == TINYUSB_MSC_STORAGE_MOUNT_APP) {
esp_err_t unmount_ret =
tinyusb_msc_set_storage_mount_point(s_ctx.storage_hdl, TINYUSB_MSC_STORAGE_MOUNT_USB);
if (unmount_ret != ESP_OK) {
ESP_LOGW(TAG, "Failed to switch storage mount point to USB during cleanup: %s",
esp_err_to_name(unmount_ret));
}
}
esp_err_t delete_ret = tinyusb_msc_delete_storage(s_ctx.storage_hdl);
if (delete_ret != ESP_OK) {
ESP_LOGW(TAG, "delete_storage during cleanup failed: %s", esp_err_to_name(delete_ret));
}
s_ctx.storage_hdl = NULL;
}
s_ctx.storage_created = false;
@@ -409,13 +461,24 @@ esp_err_t hal_storage_switch(hal_storage_media_t media)
esp_err_t ret = ESP_OK;
ret = uninstall_tinyusb_device_driver();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "tinyusb_driver_uninstall fail: %s", esp_err_to_name(ret));
hal_storage_unlock();
return ret;
}
if (s_ctx.storage_created && s_ctx.storage_hdl) {
tinyusb_msc_mount_point_t cur;
if (tinyusb_msc_get_storage_mount_point(s_ctx.storage_hdl, &cur) == ESP_OK) {
if (cur != TINYUSB_MSC_STORAGE_MOUNT_APP) {
tinyusb_msc_set_storage_mount_point(s_ctx.storage_hdl, TINYUSB_MSC_STORAGE_MOUNT_APP);
vTaskDelay(pdMS_TO_TICKS(100));
if (tinyusb_msc_get_storage_mount_point(s_ctx.storage_hdl, &cur) == ESP_OK &&
cur == TINYUSB_MSC_STORAGE_MOUNT_APP) {
ret = tinyusb_msc_set_storage_mount_point(s_ctx.storage_hdl, TINYUSB_MSC_STORAGE_MOUNT_USB);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "switch mount point to USB fail: %s", esp_err_to_name(ret));
hal_storage_unlock();
return ret;
}
vTaskDelay(pdMS_TO_TICKS(100));
}
ret = tinyusb_msc_delete_storage(s_ctx.storage_hdl);
@@ -484,7 +547,55 @@ esp_err_t hal_storage_switch(hal_storage_media_t media)
ESP_LOGW(TAG, "set_storage_callback fail: %s", esp_err_to_name(ret));
}
_mount();
ret = _mount();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Storage mount to APP failed after switch: %s", esp_err_to_name(ret));
if (s_ctx.storage_hdl) {
esp_err_t delete_ret = tinyusb_msc_delete_storage(s_ctx.storage_hdl);
if (delete_ret != ESP_OK) {
ESP_LOGW(TAG, "delete_storage after mount failure failed: %s", esp_err_to_name(delete_ret));
}
s_ctx.storage_hdl = NULL;
}
s_ctx.storage_created = false;
if (media == APP_STORAGE_MEDIA_SPIFLASH) {
storage_deinit_spiflash();
} else {
storage_deinit_sdmmc();
}
hal_storage_unlock();
return ret;
}
ret = install_tinyusb_device_driver();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "tinyusb_driver_install fail after switch: %s", esp_err_to_name(ret));
if (s_ctx.storage_hdl) {
tinyusb_msc_mount_point_t cur;
if (tinyusb_msc_get_storage_mount_point(s_ctx.storage_hdl, &cur) == ESP_OK &&
cur == TINYUSB_MSC_STORAGE_MOUNT_APP) {
esp_err_t unmount_ret =
tinyusb_msc_set_storage_mount_point(s_ctx.storage_hdl, TINYUSB_MSC_STORAGE_MOUNT_USB);
if (unmount_ret != ESP_OK) {
ESP_LOGW(TAG, "Failed to switch storage mount point to USB during install cleanup: %s",
esp_err_to_name(unmount_ret));
}
}
esp_err_t delete_ret = tinyusb_msc_delete_storage(s_ctx.storage_hdl);
if (delete_ret != ESP_OK) {
ESP_LOGW(TAG, "delete_storage after install failure failed: %s", esp_err_to_name(delete_ret));
}
s_ctx.storage_hdl = NULL;
}
s_ctx.storage_created = false;
if (media == APP_STORAGE_MEDIA_SPIFLASH) {
storage_deinit_spiflash();
} else {
storage_deinit_sdmmc();
}
hal_storage_unlock();
return ret;
}
hal_storage_unlock();
return ESP_OK;
}
+22 -11
View File
@@ -7,6 +7,7 @@
#include <cstring>
#include <cctype>
#include <cstdio>
#include <cstdlib>
static bool get_bmp_size_mem(const uint8_t *data, size_t len, int *width, int *height)
{
@@ -82,18 +83,28 @@ bool get_image_size_from_file(const char *path, int *width, int *height)
FILE *f = fopen(path, "rb");
if (!f) return false;
uint8_t buf[2048];
size_t n = fread(buf, 1, sizeof(buf), f);
constexpr size_t BUF_SIZE = 65536;
uint8_t *buf = (uint8_t *)malloc(BUF_SIZE);
if (!buf) {
fclose(f);
return false;
}
size_t n = fread(buf, 1, BUF_SIZE, f);
fclose(f);
if (n == 0) return false;
if (strcasecmp(dot, ".jpg") == 0 || strcasecmp(dot, ".jpeg") == 0) {
return get_jpg_size_mem(buf, n, width, height);
} else if (strcasecmp(dot, ".bmp") == 0) {
return get_bmp_size_mem(buf, n, width, height);
} else if (strcasecmp(dot, ".png") == 0) {
return get_png_size_mem(buf, n, width, height);
if (n == 0) {
free(buf);
return false;
}
return false;
bool ok = false;
if (strcasecmp(dot, ".jpg") == 0 || strcasecmp(dot, ".jpeg") == 0) {
ok = get_jpg_size_mem(buf, n, width, height);
} else if (strcasecmp(dot, ".bmp") == 0) {
ok = get_bmp_size_mem(buf, n, width, height);
} else if (strcasecmp(dot, ".png") == 0) {
ok = get_png_size_mem(buf, n, width, height);
}
free(buf);
return ok;
}