@@ -91,6 +91,9 @@ def __lt__(self, other) -> bool:
9191    def  __bool__ (self ) ->  bool :
9292        return  True 
9393
94+     def  __repr__ (self ) ->  str :
95+         return  f"{{func={ self .func .__name__ } { self ._periodUs } { self .expirationUs }  
96+ 
9497
9598class  _OrderedList :
9699    def  __init__ (self ) ->  None :
@@ -119,7 +122,7 @@ def __iter__(self) -> Iterable[Any]:
119122    def  __contains__ (self , item ) ->  bool :
120123        return  item  in  self ._data 
121124
122-     def  __str__ (self ) ->  str :
125+     def  __repr__ (self ) ->  str :
123126        return  str (sorted (self ._data ))
124127
125128
@@ -155,7 +158,6 @@ def __init__(self, period: wpimath.units.seconds = kDefaultPeriod) -> None:
155158        self .addPeriodic (self ._loopFunc , period = self ._periodS )
156159
157160        self ._notifier , status  =  initializeNotifier ()
158-         print (f"{ self ._notifier } { status }  )
159161        if  status  !=  0 :
160162            raise  RuntimeError (
161163                f"initializeNotifier() returned { self ._notifier } { status }  
@@ -193,33 +195,35 @@ def startCompetition(self) -> None:
193195                if  status  !=  0 :
194196                    raise  RuntimeError (f"updateNotifierAlarm() returned { status }  )
195197
196-                 currentTimeUs , status  =  waitForNotifierAlarm (self ._notifier )
198+                 self . _loopStartTimeUs , status  =  waitForNotifierAlarm (self ._notifier )
197199                if  status  !=  0 :
198200                    raise  RuntimeError (
199-                         f"waitForNotifierAlarm() returned currentTimeUs= { currentTimeUs } { status }  
201+                         f"waitForNotifierAlarm() returned _loopStartTimeUs= { self . _loopStartTimeUs } { status }  
200202                    )
201203
202-                 if  currentTimeUs  ==  0 :
204+                 if  self . _loopStartTimeUs  ==  0 :
203205                    # when HAL_StopNotifier(self.notifier) is called the above waitForNotifierAlarm 
204-                     # will return a currentTimeUs ==0 and the API requires robots to stop any loops. 
206+                     # will return a _loopStartTimeUs ==0 and the API requires robots to stop any loops. 
205207                    # See the API for waitForNotifierAlarm 
206208                    break 
207209
208-                 self ._loopStartTimeUs  =  _getFPGATime ()
209-                 self ._runCallbackAndReschedule (callback , currentTimeUs )
210+                 self ._runCallbackAndReschedule (callback )
210211
211212                #  Process all other callbacks that are ready to run 
212-                 while  self ._callbacks .peek ().expirationUs  <=  currentTimeUs :
213+                 while  self ._callbacks .peek ().expirationUs  <=  self . _loopStartTimeUs :
213214                    callback  =  self ._callbacks .pop ()
214-                     self ._runCallbackAndReschedule (callback ,  currentTimeUs )
215+                     self ._runCallbackAndReschedule (callback )
215216        finally :
217+             # pytests hang on PC when we don't force a call to self._stopNotifier() 
216218            self ._stopNotifier ()
217219
218-     def  _runCallbackAndReschedule (
219-         self , callback : _Callback , currentTimeUs : microsecondsAsInt 
220-     ) ->  None :
220+     def  _runCallbackAndReschedule (self , callback : _Callback ) ->  None :
221221        callback .func ()
222-         callback .setNextStartTimeUs (currentTimeUs )
222+         # The c++ implementation used the current time before the callback ran, 
223+         # to reschedule. By using _getFPGATime(), on a callback.func() 
224+         # that ran long we immediately push the next invocation to the 
225+         # following period. 
226+         callback .setNextStartTimeUs (_getFPGATime ())
223227        self ._callbacks .add (callback )
224228
225229    def  _stopNotifier (self ):
0 commit comments