@@ -26,6 +26,8 @@ enum State
2626 } ;
2727
2828 const string SapphireEEPROMName = "SM64 Sapphire" ;
29+ const int MaxBeatsToCheck = 200 ;
30+ const int HeartbeatLeaveaway = 10 ;
2931
3032 readonly System . Threading . Timer _timer ;
3133
@@ -34,10 +36,11 @@ enum State
3436 readonly Emulator _emulator = new Emulator ( ) ;
3537 readonly Version _payloadVersion ;
3638 Config _lastSeenEmulatorConfig = new Config ( ) ;
39+ int _heartbeatActive = 0 ;
3740 private State EmulatorState
3841 {
3942 get { return _stateValue ; }
40- set { var oldValue = _stateValue ; _stateValue = value ; if ( oldValue != _stateValue ) { UpdateEmulatorState ( ) ; } }
43+ set { var oldValue = _stateValue ; _stateValue = value ; if ( oldValue != _stateValue ) { _heartbeatActive = 0 ; UpdateEmulatorState ( ) ; } }
4144 }
4245
4346 // Used from UI thread to avoid event loops
@@ -318,30 +321,44 @@ private void PrepareHacktice()
318321 if ( ! _emulator . RefreshHacktice ( ) )
319322 return ;
320323
321- newState = State . HACKTICE_CORRUPTED ;
324+ if ( _heartbeatActive >= 0 )
322325 {
323- int status = _emulator . HackticeStatus ;
324- if ( status == Canary . HackticeStatusInit )
326+ newState = State . HACKTICE_CORRUPTED ;
325327 {
326- newState = State . HACKTICE_INJECTED ;
327- return ;
328- }
329- if ( status == Canary . HackticeStatusActive )
330- {
331- newState = _emulator . HackticeVersion == _payloadVersion ? State . HACKTICE_RUNNING : State . HACKTICE_RUNNING_CAN_UPGRADE ;
332- return ;
333- }
334- if ( status == Canary . HackticeStatusDisabled )
335- {
336- newState = State . HACKTICE_UPGRADE_DISABLED ;
337- return ;
338- }
339- if ( status == Canary . HackticeStatusUpgrading )
340- {
341- newState = State . HACKTICE_UPGRADE_DATA_WRITTEN ;
342- return ;
328+ int status = _emulator . HackticeStatus ;
329+ if ( status == Canary . HackticeStatusInit )
330+ {
331+ newState = State . HACKTICE_INJECTED ;
332+ return ;
333+ }
334+ if ( status == Canary . HackticeStatusHeartbeat )
335+ {
336+ newState = State . ROM ;
337+ return ;
338+ }
339+ if ( status == Canary . HackticeStatusActive )
340+ {
341+ newState = _emulator . HackticeVersion == _payloadVersion ? State . HACKTICE_RUNNING : State . HACKTICE_RUNNING_CAN_UPGRADE ;
342+ return ;
343+ }
344+ if ( status == Canary . HackticeStatusDisabled )
345+ {
346+ newState = State . HACKTICE_UPGRADE_DISABLED ;
347+ return ;
348+ }
349+ if ( status == Canary . HackticeStatusUpgrading )
350+ {
351+ newState = State . HACKTICE_UPGRADE_DATA_WRITTEN ;
352+ return ;
353+ }
343354 }
344355 }
356+ else
357+ {
358+ // there is a bit of leaveaway before we start complaining that hacktice does not run
359+ newState = State . HACKTICE_RUNNING ;
360+ return ;
361+ }
345362 }
346363 finally
347364 {
@@ -407,6 +424,13 @@ private void EmulatorStateUpdate(object state)
407424
408425 if ( EmulatorState >= State . HACKTICE_RUNNING )
409426 {
427+ _heartbeatActive ++ ;
428+ if ( _heartbeatActive >= MaxBeatsToCheck )
429+ {
430+ _emulator . WriteStatus ( Canary . HackticeStatusHeartbeat ) ;
431+ _heartbeatActive = - HeartbeatLeaveaway ;
432+ }
433+
410434 var userUpdatedConfig = NeedToUpdateConfig ;
411435
412436 // TODO: This logic gets complicated, separate this away
0 commit comments