fix: report the real PoR/remote-SW result of every RAM install step (v3.6.2)
The RAM installer read `por['decoded']['response_status']`, but the compact
response decoder's `decoded` only carries {number_of_commands,
last_status_word, last_response_data} - so the suffix was always empty and
every step showed the useless `por_error_`, even when the PoR was por_ok.
The PoR verdict is the top-level `response_status`.
With that fixed, the decoded details also show that the remote command's own
status word was the real verdict all along: a captured live install returned
por_ok with `last_status_word` 6700/6F00 (the card rejected every RAM APDU)
while the installer reported success.
- new `_ram_step_result()`/`_por_remote_sw()`/`_ram_remote_sw_ok()`: a step
fails on a non-por_ok PoR, on a remote SW outside the success set (9000,
61xx more data, 62xx/63xx warnings, CAFE GP "more data"), or on an
undecodable PoR (a 9000 transport SW with no PoR at all is `no_por`, not a
failure). A decoded 61xx is explicitly success, per GP/ISO.
- step records gain por_sw/por_type/por_cntr/por_data/por_raw and
`por_error`; the response carries `failed_step` and a detailed error such
as `LOAD (1/9): remote SW 6700`; the log line now prints
`status=por_ok remote_sw=6700`.
- PWA: new pure `ramStepLine()` renders e.g.
`❌ Шаг 2: LOAD (1/9) — PoR ok · remote SW 6700 (Wrong length in Lc) · 274 B / 3 SMS`
(SW meaning via the existing lookupSw decoder) and the transport SW only
when it is not 9000.
- tests: tests/test_ota_helpers.py RamPorStepTest (success set incl. 61xx,
the captured 6700 failure, no-PoR/undecodable, expanded responses);
ram.test.js ramStepLine cases.
- docs/api.md RAM install step fields + failure semantics; AGENTS updated.
603 frontend / 487 Python green; version 3.6.2; sw simple-v275.
This commit is contained in:
+35
-7
@@ -1665,7 +1665,7 @@
|
||||
// ===== Version =====
|
||||
// Single source of truth for the PWA version: shown in the header and used
|
||||
// by the server version check in pysimConnect().
|
||||
const SIMPLE_VERSION = '3.6.1';
|
||||
const SIMPLE_VERSION = '3.6.2';
|
||||
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
||||
|
||||
// ===== Tab switching =====
|
||||
@@ -8859,6 +8859,33 @@ async function ramDeleteFromExplorer(aid, withCascade) {
|
||||
await ramExplore(sp);
|
||||
}
|
||||
|
||||
// One RAM install step line: the PoR verdict plus the remote command's
|
||||
// status word (9000/61xx/62xx/63xx/CAFE are success; anything else is the
|
||||
// card's error) - the details that used to be lost behind a bare
|
||||
// "por_error_" label. The envelope/GET RESPONSE SW is only shown when it is
|
||||
// not a plain 9000.
|
||||
function ramStepLine(s, idx) {
|
||||
const ok = !s.por_error && (s.por_status === 'por_ok' || s.por_status === 'no_por');
|
||||
let line = (ok ? '\u2705' : '\u274c') + ' ' + t('Step') + ' ' + (idx + 1) + ': ' +
|
||||
s.name + ' \u2014 ';
|
||||
if (s.por_status === 'por_ok') line += t('PoR ok');
|
||||
else if (s.por_status === 'no_por') line += t('no PoR');
|
||||
else if (s.por_status && s.por_status.indexOf('por_error') === 0) {
|
||||
const legacy = s.por_status.replace(/^por_error_?/, '');
|
||||
line += t('PoR error') + (legacy ? ' ' + legacy : '');
|
||||
} else if (s.por_status) line += t('PoR error') + ' ' + s.por_status;
|
||||
else line += t('PoR unknown');
|
||||
if (s.por_sw) {
|
||||
const name = lookupSw(s.por_sw.substr(0, 2), s.por_sw.substr(2, 2), 'gp');
|
||||
line += ' \u00b7 ' + t('remote SW') + ' ' + s.por_sw + (name ? ' (' + name + ')' : '');
|
||||
}
|
||||
if (s.sw && s.sw !== '9000') line += ' \u00b7 ' + t('transport SW') + ' ' + s.sw;
|
||||
if (s.bytes && s.segments) {
|
||||
line += ' \u00b7 ' + s.bytes + ' ' + t('bytes') + ' / ' + s.segments + ' SMS';
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
async function ramInstallCap(sp) {
|
||||
const fileInput = document.getElementById('ram-cap-file');
|
||||
const file = fileInput.files[0];
|
||||
@@ -8894,12 +8921,7 @@ async function ramInstallCap(sp) {
|
||||
stepsEl.classList.remove('hidden');
|
||||
|
||||
let txt = '';
|
||||
(data.steps || []).forEach((s, idx) => {
|
||||
const mark = s.por_status === 'por_ok' ? '✅' : '❌';
|
||||
let line = mark + ' ' + t('Step') + ' ' + (idx + 1) + ': ' + s.name + ' — ' + s.por_status + ' (SW ' + s.sw + ')';
|
||||
if (s.bytes && s.segments) line += ' · ' + s.bytes + ' ' + t('bytes') + ' / ' + s.segments + ' SMS';
|
||||
txt += line + '\n';
|
||||
});
|
||||
(data.steps || []).forEach((s, idx) => { txt += ramStepLine(s, idx) + '\n'; });
|
||||
stepsEl.textContent = txt;
|
||||
|
||||
if (data.success) {
|
||||
@@ -16787,6 +16809,12 @@ const LANG_RU = {
|
||||
'default: 9000 (91?? when polling)': 'по умолчанию: 9000 (91?? при опросе)',
|
||||
'Expected data (hex, optional)': 'Ожидаемые данные (hex, опционально)',
|
||||
'PoR check': 'Проверка PoR',
|
||||
'PoR ok': 'PoR: успешно',
|
||||
'no PoR': 'PoR: нет',
|
||||
'PoR error': 'Ошибка PoR',
|
||||
'PoR unknown': 'PoR: неизвестно',
|
||||
'remote SW': 'SW команды',
|
||||
'transport SW': 'транспортный SW',
|
||||
'Any': 'Любой',
|
||||
'No PoR expected': 'PoR не ожидается',
|
||||
'On mismatch': 'При несовпадении',
|
||||
|
||||
Reference in New Issue
Block a user