stk: never shadow a paused command with a new menu selection
The stuck-card pattern: after a Back TR the card re-issues the parent menu
as a new SELECT ITEM (91XX -> FETCH, paused, awaiting TR), but the UI's
back/timeout branch ignored that response and showed the cached top menu;
the next item click then sent ENVELOPE(Menu Selection) while the card was
waiting for the TR. The card answers such an ENVELOPE with 9000 (not the
usual 91XX), and menu-select cleared the pending command without a TR,
leaving an unfinished proactive session until reset/equip.
- server: _finish_pending_menu() answers a paused command with a cancel TR
(0x10) before /api/menu-select sends its ENVELOPE and drains a 91XX
follow-up, so a new selection can never shadow an unanswered FETCH
- frontend: stkMenuRespond('back'|'timeout') renders the follow-up command
from the server response (SELECT ITEM / DISPLAY TEXT) and shows the
cached top menu only when the TR answer carries no command (9000)
- tests: finish-pending cancel TR + chain drain (Python); stkMenuRespond
back/timeout/cancel/ok rendering (frontend); help/AGENTS updated;
SW cache v107 -> v108.
This commit is contained in:
@@ -1601,6 +1601,21 @@ def _menu_send_response(server, result, item_id=None):
|
||||
return resp, 200
|
||||
|
||||
|
||||
def _finish_pending_menu(server, scc):
|
||||
"""A new menu selection must never shadow a FETCHed command that awaits its
|
||||
TERMINAL RESPONSE: answer it with a cancel TR (0x10) first, then drain any
|
||||
follow-up proactive command so the card is ready for the new selection."""
|
||||
pd = server.stk_pending
|
||||
if not pd:
|
||||
return
|
||||
sys.stderr.write('MENU-SELECT: finishing pending cmd=%02x type=%02x with cancel TR\n'
|
||||
% (pd['cmd_num'], pd['cmd_type']))
|
||||
resp, _ = _menu_send_response(server, 'cancel', None)
|
||||
sw = (resp or {}).get('sw', '')
|
||||
if sw.startswith('91'):
|
||||
_handle_proactive_chain(scc, sw)
|
||||
|
||||
|
||||
class PysimHandler(BaseHTTPRequestHandler):
|
||||
def _send_json(self, data, status=200):
|
||||
self.send_response(status)
|
||||
@@ -2179,6 +2194,7 @@ class PysimHandler(BaseHTTPRequestHandler):
|
||||
return
|
||||
body = self._read_body()
|
||||
self._log_req(body)
|
||||
_finish_pending_menu(self.server, scc)
|
||||
item_id = body.get('item_id', 0)
|
||||
if not isinstance(item_id, int):
|
||||
item_id = int(item_id)
|
||||
|
||||
Reference in New Issue
Block a user