Merge branch 'main' of ssh://892887cvmk08.aicp.io:24928/orisys-tech/orisys-app
This commit is contained in:
@@ -111,7 +111,16 @@ class AxisState:
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BusStatus:
|
||||
"""Bus-level state, from the ``.bas`` program's globals."""
|
||||
"""Bus-level state, from the ``.bas`` program's globals.
|
||||
|
||||
``verified_this_session`` exists because ``BUS_TYPE``, ``Bus_InitStatus``
|
||||
and ``Bus_TotalAxisnum`` are ZBasic **globals**: they live in controller
|
||||
memory and survive the program finishing, a reconnect, and (with the ROM
|
||||
program reloading) a reboot. ``Bus_InitStatus == 1`` therefore means "a scan
|
||||
completed at some point", not "this bus is live now". A controller that was
|
||||
power-cycled but not re-initialised still reports 1, and reporting that as
|
||||
初始化成功 is what made a bus which had never been set up look ready.
|
||||
"""
|
||||
|
||||
bus_type: BusType = "unknown"
|
||||
init_status: int = INIT_RUNNING
|
||||
@@ -121,6 +130,14 @@ class BusStatus:
|
||||
bas_loaded: bool = False
|
||||
init_started_at: float | None = None
|
||||
message: str = ""
|
||||
#: False until this session has seen the state machine through a run it
|
||||
#: started (a download or a re-init). An adopted latch starts False.
|
||||
verified_this_session: bool = False
|
||||
|
||||
@property
|
||||
def adopted_unverified(self) -> bool:
|
||||
"""The latch says initialised, but nothing here has confirmed it."""
|
||||
return self.init_status == INIT_OK and not self.verified_this_session
|
||||
|
||||
@property
|
||||
def initialized(self) -> bool:
|
||||
|
||||
@@ -401,7 +401,9 @@ class MotionService:
|
||||
self._spec = spec
|
||||
logger.info("Connected: %s via %s", spec.describe(), self._transport.source)
|
||||
# A controller may already have a BAS program running from a previous
|
||||
# session; adopt it rather than claiming the bus is uninitialised.
|
||||
# session; adopt it rather than claiming the bus is uninitialised. The
|
||||
# adopted state is *not* marked verified: its globals are a latch, and
|
||||
# nothing in this session has yet seen a scan happen.
|
||||
self._adopt_existing_bas(bas_path=bas_path)
|
||||
return MotionResult.success(f"已连接 {spec.describe()}" if self._is_zh else f"Connected {spec.describe()}")
|
||||
|
||||
@@ -469,12 +471,14 @@ class MotionService:
|
||||
|
||||
self._bas_loaded = True
|
||||
self._init_started_at = time.monotonic()
|
||||
# A download is a run this session owns, so its outcome can be trusted.
|
||||
self._bus = BusStatus(
|
||||
bus_type=self._bus.bus_type,
|
||||
init_status=INIT_RUNNING,
|
||||
bas_path=filename,
|
||||
bas_loaded=True,
|
||||
init_started_at=self._init_started_at,
|
||||
verified_this_session=True,
|
||||
)
|
||||
# Read BUS_TYPE so the SDO/RTEX panels enable for the right family.
|
||||
try:
|
||||
@@ -541,6 +545,7 @@ class MotionService:
|
||||
bas_path=self._bus.bas_path,
|
||||
bas_loaded=True,
|
||||
init_started_at=self._init_started_at,
|
||||
verified_this_session=True,
|
||||
)
|
||||
# Re-read BUS_TYPE now: the program may be a different family than the
|
||||
# one the previous session left behind.
|
||||
@@ -662,7 +667,13 @@ class MotionService:
|
||||
)
|
||||
return
|
||||
|
||||
verified = bus.verified_this_session
|
||||
if init_status != INIT_RUNNING:
|
||||
# A run this session owned has just settled: that is the only
|
||||
# evidence available that the state machine actually moved, rather
|
||||
# than the globals having been left at their last values.
|
||||
if self._init_started_at is not None:
|
||||
verified = True
|
||||
self._init_started_at = None
|
||||
try:
|
||||
node_count = self._transport.bus_node_count(0)
|
||||
@@ -679,6 +690,7 @@ class MotionService:
|
||||
bas_loaded=True,
|
||||
init_started_at=self._init_started_at,
|
||||
message=message,
|
||||
verified_this_session=verified,
|
||||
)
|
||||
|
||||
def _read_axis(self, axis: int) -> AxisState:
|
||||
@@ -967,4 +979,7 @@ def _replace_bus_type(bus: BusStatus, bus_type: BusType) -> BusStatus:
|
||||
bas_loaded=bus.bas_loaded,
|
||||
init_started_at=bus.init_started_at,
|
||||
message=bus.message,
|
||||
# Carried, not reset: re-reading BUS_TYPE is incidental, and dropping
|
||||
# this would make a just-verified init look unverified again.
|
||||
verified_this_session=bus.verified_this_session,
|
||||
)
|
||||
|
||||
@@ -36,6 +36,7 @@ _STATE_KEYS = {
|
||||
_STATE_TONES = {
|
||||
"bus.state_running": "warn",
|
||||
"bus.state_ok": "ok",
|
||||
"bus.state_unverified": "warn",
|
||||
"bus.state_failed": "error",
|
||||
"bus.state_timeout": "error",
|
||||
}
|
||||
@@ -140,10 +141,19 @@ class BusPanel(QGroupBox):
|
||||
self.choose_button.setEnabled(True)
|
||||
|
||||
def set_status(self, bus: BusStatus, *, now: float | None = None) -> None:
|
||||
"""Render the bus state, including the vendor's timeout case."""
|
||||
"""Render the bus state, including the vendor's timeout case.
|
||||
|
||||
An *adopted* ``Bus_InitStatus == 1`` is shown as unverified rather than
|
||||
as success. The value is a ZBasic global that survives the program and a
|
||||
reboot, so it proves a scan happened at some point, not that this bus is
|
||||
live now — and calling that 初始化成功 is what made a machine which had
|
||||
never been set up look ready to move.
|
||||
"""
|
||||
key = _STATE_KEYS.get(bus.init_status, "bus.state_pending")
|
||||
if bus.init_status == INIT_FAILED and bus.message and "超时" in bus.message:
|
||||
key = "bus.state_timeout"
|
||||
elif bus.adopted_unverified:
|
||||
key = "bus.state_unverified"
|
||||
self._state_text = t(key)
|
||||
self._state_tone = _STATE_TONES.get(key, "muted")
|
||||
self.state_value.setText(self._state_text)
|
||||
@@ -156,7 +166,7 @@ class BusPanel(QGroupBox):
|
||||
self.type_value.setText(t(type_keys.get(bus.bus_type, "bus.type_unknown")))
|
||||
self.nodes_value.setText(str(bus.node_count))
|
||||
self.axes_value.setText(str(bus.total_axes))
|
||||
self.message_label.setText(bus.message)
|
||||
self.message_label.setText(bus.message or (t("bus.unverified_hint") if bus.adopted_unverified else ""))
|
||||
|
||||
# ------------------------------------------------------------- translations
|
||||
|
||||
|
||||
@@ -224,6 +224,12 @@ class StatusStrip(QFrame):
|
||||
if not connected:
|
||||
self.chip_init.setText(t("bus.state_pending"))
|
||||
self.chip_init.set_tone("muted")
|
||||
elif snapshot.bus.adopted_unverified:
|
||||
# The controller's initialisation global is a latch that survives the
|
||||
# program and a reboot; without a run this session, "initialised" is
|
||||
# not something this process has seen. Say so rather than claim it.
|
||||
self.chip_init.setText(t("bus.state_unverified"))
|
||||
self.chip_init.set_tone("warn")
|
||||
elif snapshot.bus.initialized:
|
||||
self.chip_init.setText(t("bus.state_ok"))
|
||||
self.chip_init.set_tone("ok")
|
||||
|
||||
@@ -878,7 +878,9 @@ class AutoCalMainWindow(QMainWindow):
|
||||
t("status.poll_paused") if self.status_strip.paused else t("status.poll_ok"),
|
||||
t("status.poll_every", ms=self.poller.interval_ms),
|
||||
]
|
||||
if snapshot.bus.init_status == 1:
|
||||
if snapshot.bus.adopted_unverified:
|
||||
parts.append(t("bus.state_unverified"))
|
||||
elif snapshot.bus.init_status == 1:
|
||||
parts.append(t("bus.state_ok"))
|
||||
if self._last_error:
|
||||
parts.append(f"{t('status.last_error')}: {self._last_error}")
|
||||
|
||||
Reference in New Issue
Block a user