diff --git a/src/pykit/loggedrobot.py b/src/pykit/loggedrobot.py index 5039f7a..414be30 100644 --- a/src/pykit/loggedrobot.py +++ b/src/pykit/loggedrobot.py @@ -35,7 +35,7 @@ def __init__(self): # Because in "robotpy test" this code starts at time 0 # and hal.waitForNotifierAlarm returns (current_time_or_stopped, status) # with current_time_or_stopped assigned to 0 when hal.stopNotifier is called - # or when the the current time is 0, and hal.stopNotifier is signal to + # or when the current time is 0, and hal.stopNotifier is signal to # exit the infinite loop, the stop is prematurely detected at time 0. # Force the program to wait until self._periodUs for the first periodic loop # so that current_time_or_stopped will contain a non-zero current time and the @@ -58,6 +58,14 @@ def startCompetition(self) -> None: This method replaces the standard `IterativeRobotBase.startCompetition` to inject logging and precise timing control. """ + + Logger.startReciever() + startCompetitionTime = RobotController.getFPGATime() + Logger.periodicAfterUser(startCompetitionTime, 0) + stop = Logger.periodicBeforeUser() + if stop: + Logger.end() + return self.robotInit() if self.isSimulation(): @@ -68,8 +76,6 @@ def startCompetition(self) -> None: print("Robot startup complete!") hal.observeUserProgramStarting() - Logger.startReciever() - while True: # Wait for next cycle using HAL notifier for precise timing if self.useTiming: @@ -93,7 +99,7 @@ def startCompetition(self) -> None: # Run logger pre-user code (load inputs from log or sensors) periodicBeforeStart = RobotController.getFPGATime() - Logger.periodicBeforeUser() + stop = Logger.periodicBeforeUser() # Execute user periodic code and measure timing userCodeStart = RobotController.getFPGATime() @@ -104,3 +110,7 @@ def startCompetition(self) -> None: Logger.periodicAfterUser( userCodeEnd - userCodeStart, userCodeStart - periodicBeforeStart ) + if stop: + break + + Logger.end() diff --git a/src/pykit/logger.py b/src/pykit/logger.py index bf08ee2..5585218 100644 --- a/src/pykit/logger.py +++ b/src/pykit/logger.py @@ -246,18 +246,16 @@ def getTimestamp(cls) -> int: :return: The current timestamp in microseconds. """ - if cls.isReplay(): - return cls.entry.getTimestamp() - # RobotController.getFPGATime may be untyped; ensure int - return int(RobotController.getFPGATime()) + return cls.entry.getTimestamp() @classmethod - def periodicBeforeUser(cls): + def periodicBeforeUser(cls) -> bool: """ Called periodically before the user's robot code. This method updates the log table with new data, either from the replay source or from the live robot hardware. """ + stop = False cls.cycleCount += 1 if cls.running: entryUpdateStart = RobotController.getFPGATime() @@ -273,9 +271,7 @@ def periodicBeforeUser(cls): print( "[ERROR] This robot did not start properly, is the replay logfile from PyKit?" ) - else: - cls.end() - raise SystemExit(0) + stop = True dsStart = RobotController.getFPGATime() # In replay mode, simulate driver station inputs from log @@ -302,6 +298,7 @@ def periodicBeforeUser(cls): "Logger/DashboardInputsMS", (dashboardInputEnd - dashboardInputStart) / 1000.0, ) + return stop @classmethod def periodicAfterUser(cls, userCodeLength: int, periodicBeforeLength: int): diff --git a/src/pykit/wpilog/wpilogwriter.py b/src/pykit/wpilog/wpilogwriter.py index c821753..ba6e504 100644 --- a/src/pykit/wpilog/wpilogwriter.py +++ b/src/pykit/wpilog/wpilogwriter.py @@ -36,7 +36,7 @@ class WPILOGWriter(LogDataReciever): folder: str filename: str randomIdentifier: str - dsAttachedTime: int = 0 + dsAttachedTime: float = 0.0 autoRename: bool logDate: datetime.datetime | None logMatchText: str @@ -172,7 +172,7 @@ def putTable(self, table: LogTable) -> None: ) > 5 or RobotBase.isSimulation(): self.logDate = datetime.datetime.now() else: - self.dsAttachedTime = 0 + self.dsAttachedTime = 0.0 matchType: MatchType match table.get("DriverStation/MatchType", 0):