diff --git a/posadmesh-tools/flasher/README.md b/posadmesh-tools/flasher/README.md index bb9a39a2..97de073f 100644 --- a/posadmesh-tools/flasher/README.md +++ b/posadmesh-tools/flasher/README.md @@ -85,6 +85,16 @@ nginx -t && systemctl reload nginx - определение чипа при подключении, журнал операций, прогресс, кнопка перезагрузки; - для nRF52 (`.uf2`, `.zip`) — скачивание и инструкция: копирование на UF2-диск или DFU через nRF Connect. +## Грабли + +- **`A.charCodeAt is not a function` при прошивке ESP32.** esptool-js 0.5.x ожидает содержимое + файла как «двоичную строку»: внутри `writeFlash` вызывается `bstrToUi8(data)`, то есть + `data.charCodeAt(i)`. Если передать `Uint8Array`, запись падает. В `app.js` байты приводит + `bytesToBinaryString()` (кусками по 32 КБ, чтобы не упереться в лимит аргументов). +- **Браузер держит старый `app.js`.** Для `location /flasher/` в nginx стоит + `Cache-Control: no-cache`, а подключение в `index.html` идёт с версией (`app.js?v=...`). + При правке скрипта версию нужно поднять, иначе браузер возьмёт старый файл из кэша. + ## Ограничения - прошивка из браузера возможна только для ESP32: nRF52 требует UF2-диска или DFU; diff --git a/posadmesh-tools/flasher/app.js b/posadmesh-tools/flasher/app.js index 6a2f80d2..4bf42345 100644 --- a/posadmesh-tools/flasher/app.js +++ b/posadmesh-tools/flasher/app.js @@ -213,13 +213,30 @@ async function connect() { } } +// esptool-js (0.5.x) ожидает содержимое прошивки как «двоичную строку» (binary string): +// внутри writeFlash вызывается bstrToUi8(data), то есть data.charCodeAt(i). Если передать +// Uint8Array, падает с "data.charCodeAt is not a function" — поэтому конвертируем сами. +function bytesToBinaryString(bytes) { + let out = ''; + const CHUNK = 0x8000; // чтобы String.fromCharCode.apply не упёрся в лимит аргументов + for (let i = 0; i < bytes.length; i += CHUNK) { + out += String.fromCharCode.apply(null, bytes.subarray(i, i + CHUNK)); + } + return out; +} + async function fetchFirmware(file) { log('Загрузка ' + file.name + ' (' + human(file.size) + ')…'); const res = await fetch(file.url, { cache: 'no-store' }); if (!res.ok) throw new Error('не удалось скачать файл: HTTP ' + res.status); const buf = await res.arrayBuffer(); - log('Получено ' + human(buf.byteLength)); - return new Uint8Array(buf); + const bytes = new Uint8Array(buf); + log('Получено ' + human(bytes.length) + ', подготовка данных…'); + const data = bytesToBinaryString(bytes); + if (data.length !== bytes.length) { + throw new Error(`данные повреждены при подготовке: ${data.length} вместо ${bytes.length} байт`); + } + return data; } async function flash() { diff --git a/posadmesh-tools/flasher/index.html b/posadmesh-tools/flasher/index.html index 7b642bc5..c5e946f7 100644 --- a/posadmesh-tools/flasher/index.html +++ b/posadmesh-tools/flasher/index.html @@ -112,6 +112,6 @@ - +