include common.inc
 
-settling_timeout equ 10000 ; us
+settling_timeout       equ      10000 ; us
+
+stop_timeout           equ     500000 ; us
+stopflash_timeout      equ      25000 ; us
+retry_timeout          equ      50000 ; us
+persist_timeout                equ      90000 ; us
 
  udata_acs
-settling       res     1
+settling       res     1 ; all counters are 0 if stopped
+stop_wait      res     1 ;  or otherwise count down
+retry_wait     res     1
 
  code
 
 ;======================================================================
+;
 ; POLARISING/SETTLING:
 ;
 ;              NMRA            flag_p. settling        Booster PWM
 ;
-; Normal       running         0       0x00            mark
-; Polarising   paused          1       0x00            space
-; Settling     paused          1       >0, count down  space
+; Normal       running         0       stopped         mark
+; Polarising   paused          1       stopped         space
+; Settling     paused          1       running         space
 ;
 ; NMRA is paused by disabling timer 0 intr; when we restart,
 ; we restart the current message.
 ;--------------------
 power_polarising_begin
        pin_l   p0_booster_pwm
-       bc_f    INTCON, TMR0IE
+       bc_f    INTCON, TMR0IE ; disables NMRA interrupt
        bs_f    flags, flags_polarising
        clr_f   settling
        return
        ; settle timeout complete:
 
        bc_f    flags, flags_polarising
-       intr_mask
        call    nmra_restartmessage
-       intr_unmask
+       bs_f    INTCON, TMR0IE ; reenables NMRA interrupt
        goto    i2c_consider_restartread
 
 ;======================================================================
 ;
 ; FAULTS AND POWER:
 ;
-;              Shutdown CDU    Fault timeout   User Fault      Next states
-; Off          shutdown off    stopped         off             On*, Fault+
-; On           power-up on     stopped         off             Fault, Off*
-; Fault                shutdown off    500ms           1/2x50ms        Retry
-; Retry                power-up off    50ms            on              Persists, Off
-; Persists     shutdown off    50ms            on              Retry
+;              Shutdown  CDU   Timeout User Fault      Next states
+;
+; Off          shutdown  off   none    off             *On (or +Fault)
+; On           power-up  on    none    off             Fault, or *Off
+; Stopping     shutdown  off   500ms   50% 1/50ms      ->Retry
+; Retry                power-up  off   50ms    off             ->Off, or Persists
+; Persists     shutdown  off   90ms    on              ->Retry
 ;                                                      * = when host instructs
 ;                                                      + = lost race, only
+;                                                      -> = after timeout
+;
+;              shutdown LAT    stop_wait       retry_wait
+;
+; Off          H (shutdown)    stopped         stopped
+; On           L (power-up)    stopped         stopped
+; Stopping     H (shutdown)    before Retry    for LED flash
+; Retry                L (power-up)    stopped         before Off
+; Persists     H (shutdown)    stopped         before retry
+;
+;                              (uses tickdiv)  (uses tick)
 
-command_power
-
-
-;  C           1 iff command is ON             undefined
- tell on or off
+;--------------------
+power_fault_init
+       bs_f    INTCON2, INTEDG1 ; rising edge
+       bc_f    INTCON3, INT1IP
+       bc_f    INTCON3, INT1IF
+       bs_f    INTCON3, INT1IE
+       clr_f   stop_wait
+       clr_f   retry_wait
+       pin_h   booster_shutdown
+       pin_vl  p0_booster_userfault
+       pin_z   p0_booster_userfault
+       ; now we are Off
+       return
 
-on on:
- start nmra with empty buffers
- turn booster on
- turn cdu on
+;--------------------
+command_power
+       bra_nc  command_power_off
+       ; command is ON:
+
+; Off -> On; noop in other states
+       pinlat_ifh p0_booster_shutdown
+       return  ; On or Retry
+       ; might be Off, Stopping or Persists:
+
+       tst_f_ifnz retry_wait
+       return  ; that deals with Stopping or Persists
+       ; must be Off:
+
+       pin_l   p0_booster_shutdown
+       goto    cdu_on
+
+;----------
+command_power_off
+; On -> Off; noop in other states
+       pinlat_ifl p0_booster_shutdown
+       return  ; Off, Stopping or Persists
+       ; might be On or Retry:
+
+       tst_f_ifnz retry_wait
+       return  ; that deals with Retry
+       ; must be On:
+power_off_now
+       pin_h   p0_booster_shutdown
+       goto    cdu_off
 
+;--------------------
+power_fault_intrl
+       bt_f_if1 INTCON3, INT1IF
+       return
+       ; we have a fault:
 
+       tst_f_ifz retry_wait
+       bra     power_stop ; we were Off or On, goto Stopping
+       ; must be Stopping, Retry or Persists:
 
+       tst_f_ifnz stop_wait
+       bra     power_stop ; we were already Stopping; restart timer
+       ; might be Retry or Persists, goto Persists (restarting any timer):
 
-       panic   morse_UEC
+       rcall   power_off_now
+       mov_lw  persist_timeout / tick_us
+       mov_wf  retry_wait
+       return
 
-;power_on ???
-; from cebpic/nmra-stream.asm's setup
-       bcf     PORTB,2,0       ; booster shutdown L
-       bcf     TRISB,2,0       ; booster shutdown not-Z
+;--------------------
+power_fault_tick
+       tst_f_ifnz retry_wait
+       dec_f_ifnz retry_wait
+       return
+       ; retry_wait was running but has just reached zero;
+       ; we were in Stopping, Retry or Persists:
+
+       tst_f_ifnz stop_wait
+       bra     power_stop_doflash ; that was Stopping, just flash the LED
+       ; must be Retry or Persists:
+
+       pinlat_ifl p0_booster_shutdown
+       bra     power_retry ; we were in Persists, now we can try again
+       ; we were in Retry but it didn't work:
+; go to Persists:
+       pin_h   p0_booster_shutdown
+       mov_lw  persist_timeout / tickdiv_us
+       mov_wf  retry_wait
+       pin_nz  p0_booster_userfault
+       return
 
-       bcf     PORTB,0,0       ; user fault L or Z
+;----------
+power_stop
+       rcall   power_off_now
+       mov_lw  stop_timeout / tickdiv_us
+       mov_wf  stop_wait
+       pin_z   p0_booster_userfault
+       mov_lw  b'00000111'
+       call    serial_addbyte
+power_stop_doflash
+       pin_znz p0_booster_userfault
+       mov_lw  stopflash_timeout / tickdiv_us
+       mov_wf  retry_wait
+       return
 
- pause nmra
- 
-       panic   morse_UER
+;--------------------
+power_fault_tickdiv
+       tst_f_ifnz stop_wait
+       dec_f_ifnz stop_wait
+       return
+       ; stop_wait was running but has just reached zero;
+       ; we were in Stopping, now we can Retry:
+power_retry
+       mov_lw  retry_timeout / tickdiv_us
+       mov_wf  retry_wait
+       pin_l   p0_booster_shutdown
+       pin_z   p0_booster_userfault
+       return
 
+;--------------------
 power_panichook
-       panic   morse_UEP
+       pin_h   p0_booster_shutdown
+       pin_l   p0_booster_pwm
+       pin_z   p0_booster_userfault
+       return
 
 ;======================================================================
  include final.inc