core: services: ardupilot_manager: Return none if board path is gone - #4351
core: services: ardupilot_manager: Return none if board path is gone#4351patrickelectric wants to merge 1 commit into
Conversation
Automated PR Review0. Summary
Fixes issue #1974 by making 1. Correctness & Implementation Bugs
6. Code Quality & Style
7. Tests
Generated by PR Review Bot. This is advisory, a human reviewer must still approve. |
joaoantoniocardoso
left a comment
There was a problem hiding this comment.
While this does produce the desired effect for the client (BlueOS UI), I'm not happy with how/where it is being implemented (in the API layer): it creates a gap between the internal state and the public representation, which usually is not the best move.
I'd say we should correct the internal state instead of the API.
9b49932 to
67c6a01
Compare
|
@joaoantoniocardoso Updated. |
GET /board keeps the last USB board after unplug. Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
0cf2c8b to
ee713ca
Compare
|
Right. You basically moved the code around. We are increasing the state size by adding a layer on top of the |
I'm open for suggestions. |
Agreed, my stance is to check whether we are adding a state because it's now easy or adding a state because it's the representation model we want. My suggestion is to study the input side, because of the following experiment:
Which to me means we do have the mechanism in place, just not wired to detect the board removal at runtime. |
The message that you are pointing just check if the selected board exist in the listed boards, not that's truly connected. |
|
Ok, and it doesn't show Pixhawk on the UI after restarting the service? The model seems to know when to offer Pixhawk, just not at runtime. |
no, this is the current_board, if the board does not exist anymore, we don't change the current_board. |
|
It actually offers Pixhawk at runtime if I connect the Pixhawk after initiating the service. So what it is lacking is to "unoffer"? It should, though 🤔 |
|
Perhaps: diff --git a/core/services/ardupilot_manager/autopilot_manager.py b/core/services/ardupilot_manager/autopilot_manager.py
index daea287f9..9ea828a4c 100644
--- a/core/services/ardupilot_manager/autopilot_manager.py
+++ b/core/services/ardupilot_manager/autopilot_manager.py
@@ -195,7 +195,25 @@ class AutoPilotManager(metaclass=Singleton):
async def auto_restart_ardupilot(self) -> None:
"""Auto-restart Ardupilot when it's not running but was supposed to."""
while True:
- needs_restart = self.should_be_running and not self.is_running()
+ detected = None
+ if not self._restart_lock.locked():
+ detected = await self.available_boards()
+ board = self._current_board
+ if board is not None and self._listed_as(board, detected) is None:
+ logger.info(f"{board.name} is no longer detected.")
+ self._current_board = None
+ try:
+ await self.mavlink_manager.stop()
+ except Exception as error:
+ logger.warning(f"Failed to stop Mavlink manager after board disconnect: {error}")
+
+ needs_restart = False
+ if detected is not None and self.should_be_running and not self.is_running():
+ try:
+ self.get_board_to_be_used(detected)
+ needs_restart = True
+ except RuntimeError:
+ pass
if needs_restart:
logger.debug("Restarting ardupilot...")
try:
@@ -487,16 +505,24 @@ class AutoPilotManager(metaclass=Singleton):
raise NoPreferredBoardSet("Preferred board not set yet.")
return FlightController(**preferred_board)
+ @staticmethod
+ def _listed_as(reference: FlightController, boards: List[FlightController]) -> Optional[FlightController]:
+ # Compare connected boards with saved board, excluding path (which can change between sessions)
+ for board in boards:
+ if reference.dict(exclude={"path"}).items() <= board.dict().items():
+ return board
+ return None
+
def get_board_to_be_used(self, boards: List[FlightController]) -> FlightController:
"""Check if preferred board exists and is connected. If so, use it, otherwise, choose by priority."""
try:
preferred_board = self.get_preferred_board()
logger.debug(f"Preferred flight-controller is {preferred_board.name}.")
- for board in boards:
- # Compare connected boards with saved board, excluding path (which can change between sessions)
- if preferred_board.dict(exclude={"path"}).items() <= board.dict().items():
- return board
+ listed = self._listed_as(preferred_board, boards)
+ if listed is not None:
+ return listed
logger.debug(f"Flight-controller {preferred_board.name} not connected.")
+ raise RuntimeError(f"Flight-controller {preferred_board.name} not connected.")
except NoPreferredBoardSet as error:
logger.warning(error)
~ |
GET /board keeps the last USB board after unplug.
Fix #1974