include         program+clocks.inc
        include         i2clib.incm
 
+tickdiv equ 16
+tickdiv_us equ tick_us * tickdiv
+
 ;----------------------------------------------------------------------
 ; Common conventions for function register notation:
 
 ;
 ;                      Master                  Slave
 ;  Timer 0             nmra                    Disabled
-;  Timer 2             tick: 10ms, int. low    -
+;  Timer 2             tick, int. low          -
 ;  Timer 1             -                       -
 ;  CCP1                        -                       -
 ;  Timer 3             point fire timer        point fire timer
 
 ; TRACK POWER AND SHORT CIRCUIT
 
  include common.inc
+
+settling_timeout equ 10000 ; us
+
+ udata_acs
+settling       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
+;
+; NMRA is paused by disabling timer 0 intr; when we restart,
+; we restart the current message.
+;
+;----------------------------------------------------------------------
+
+;--------------------
+power_polarising_init
+       clr_f   settling
+       return
+
+;--------------------
+power_polarising_begin
+       pin_l   p0_booster_pwm
+       bc_f    INTCON, TMR0IE
+       bs_f    flags, flags_polarising
+       clr_f   settling
+       return
+
+;--------------------
+power_polarising_settling
+; idempotent
+       tst_f_ifnz settling
+       return
+       mov_lw  settling_timeout / tick_us
+       mov_wf  settling
+       return
+
+;--------------------
+power_polarising_tick
+       tst_f_ifnz settling
+       dec_f_ifnz settling ; decrement if not zero
+       return ; return if not dec'd, or if decrement didn't make zero
+       ; settle timeout complete:
+
+       bc_f    flags, flags_polarising
+       intr_mask
+       call    nmra_restartmessage
+       intr_unmask
+       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
+;                                                      * = when host instructs
+;                                                      + = lost race, only
+
 command_power
+
+
 ;  C           1 iff command is ON             undefined
+ tell on or off
+
+on on:
+ start nmra with empty buffers
+ turn booster on
+ turn cdu on
+
+
+
+
        panic   morse_UEC
 
 ;power_on ???
 
        bcf     PORTB,0,0       ; user fault L or Z
 
-power_polarising
+ pause nmra
+ 
        panic   morse_UER
 
 power_panichook
 
 sub do_T1ov { do_T13ov(1); }
 sub do_T3ov { do_T13ov(3); }
 
+sub provide_interval ($$$$) {
+    my ($iname, $thisval, $unitname, $unitval) = @_;
+    my ($inthisunit, $inthisunitint);
+    $inthisunit= $thisval / $unitval;
+    return if $inthisunit > 256000000.0;
+    $inthisunitint= sprintf "%d", $inthisunit;
+    return if abs(($inthisunitint - $inthisunit) / $inthisunit) > 0.001;
+    p("${iname}_${unitname} equ $inthisunitint\n");
+}
+
 sub doline () {
     my ($orgname,$mswant,$specd,$unit,$how);
     chomp;
     if ($unit =~ m/u/) { $interval *= 1.e-6; }
     if ($unit =~ m/n/) { $interval *= 1.e-9; }
     if ($unit =~ s/Hz//) { $interval = 1.0 / $interval; }
+    p(";========== $name ($specd, $interval) ==========\n");
+    provide_interval($orgname, $interval, 'us', 1.e-6);
+    provide_interval($orgname, $interval, 'ms', 1.e-3);
+    provide_interval($orgname, $interval, 's', 1.0);
     foreach $ms (qw(m s)) {
        next unless $mswant =~ m/$ms/i;
        $msclock= "${ms}clock";
        die $msclock unless exists $defs{$msclock};
        $msclock= $defs{$msclock};
        $name = $orgname.'_'.($ms eq 'm' ? 'master' : 'slave');
-       p(";---------- $name ($specd, $interval) ----------\n");
        &{ "do_$how" };
     }
 }
 
        bra     arrange_write
 nextslave_nowrite
        ; no writing needed, we consider reading:
+       bt_f_if1 flags, flags_polarising
+       return  ; do not scan while booster PWM is off while polarising
+               ; to avoid all trains disappearing and reappearing
+
        neg_fw  outmsg_begin
        add_wfw outmsg_end
        and_lw  outbuf_size - 1
 
        bs_fa   nmractrl,nextaction
        bs_fa   nmractrl,transmitbit
 
+nmra_restartmessage    ; Entrypoint from power_polarising_tick, at end
+                       ;  of settle time.  Goes back to beginning of
+                       ;  current message (if any) and retransmits it.
+                       ;  Also, enables booster PWM and Timer 0 interrupts.
+       mov_lw  0x0f
+       and_wff totrack
+
 ; initialise totrackbit bitmask
        mov_lw  0x80
        mov_wfa totrackbit      ; make bit mask be 1000 0000
 
 ;...
 ;-----
 cdu_discharged
-       mov_lw  cdu_timeout / 10 ; time in ms, converted to 10ms ticks
+       mov_lw  (cdu_timeout * 1000) / tickdiv_us + 1
        mov_wf  cducharging
        return
 
        return
 
 ;--------------------
-cdu_tick
+cdu_tickdiv
        bt_f_if0 LATB, p0_cdu_enable >> 4
        return
 
 
  extern points_getwritebyte
  extern got_pointed
  extern cdu_init
- extern cdu_tick
+ extern cdu_tickdiv
  extern cdu_on
  extern cdu_off
  extern cdu_panichook
 
        call    serialtxfc_init
        call    mascan_init
        call    tick_init
+       call    power_polarising_init
        return
 
 ;----------------------------------------
 
 
 #morse         MS      T0ov16          66ms
 points         MS      T3ov            10ms
-tick           MS      T2period        10ms
+tick           MS      T2period        1ms
 
 ; now we're exiting from the loop in when_reverse_message_found
        pop      ; that disposes of the call to `board'
 
-       call    power_polarising
+       call    power_polarising_begin
 
        mov_fw  polarity_cmds ; there's always a board 0, us
        call    polarity_local_do
                                ; W = 0000000? C=0  no existing command
                                ; W = 1000000? C=0  sentinel
        bra_nn  polarity_needwrite_loop
-       bt_f_if0 STATUS, C
-       return ; we found the sentinel
-       ; we found a pic to tell to polarise:
+       bt_f_if1 STATUS, C
+       bra     polarity_needwrite_found
+       ; we found the sentinel:
 
+       bt_f_if0 flags, flags_polarising
+       return
+       goto    power_polarising_alldone
+
+polarity_needwrite_found
        mov_fw  FSR1L
        add_lw  -polarity_cmds
        pop
 
 ; TICK - REGULAR 10MS TIMER INTERRUPT
 ;
 ; after tick_init, and after interrupts enabled,
-; we call <foo>_tick every 10ms.
+; we call <foo>_tick every 1ms and <foo>_tickdiv every <tickdiv>ms.
 
  include common.inc
- code
 
+udata_acs
+tickdiv_count  res     1
+
+ code
 ;----------------------------------------
 tick_init
 ;  Timer 2             any                     used for tick
        bc_f    IPR1, TMR2IP ; low priority
        bs_f    IPR1, TMR2IE ; enable interrupts
        bs_f    T2CON, TMR2ON ; enable timer
+       mov_lw  tickdiv
+       mov_wf  tickdiv_count
        return
 
 ;----------------------------------------
        bc_f    PIR1, TMR2IF
 
        ; add calls to <foo>_tick here:
-       call    cdu_tick
+       call    power_polarising_tick
+       call    power_fault_tick
        ; end of list of calls to <foo>_tick
 
+       dec_f_ifz tickdivcount
+       bra     tickdiv_do
+
+       intrl_handled_nostack
+
+;----------------------------------------
+tickdiv_do
+       ; add calls to <foo>_tickdiv here:
+       call    cdu_tickdiv
+       ; end of list of calls to <foo>_tickdiv
+
+       mov_lw  tickdiv
+       mov_wf  tickdiv_count
        intrl_handled_nostack
 
 ;----------------------------------------------------------------------
 
 picno          res     1       ; from first idlocs byte
 
 idloc1         res     1       ; from 2nd idlocs byte; bit 7 is master:
-idloc1_master  equ     7
-idloc1_boarddet        equ     6
+idloc1_master          equ 7
+idloc1_boarddet                equ 6
 
 acknmra                res     1       ; must tell host about NMRA buffer state
 flags          res     1       ; miscellaneous state flags
+flags_polarising       equ 6
 
 t              res     1       ; general temporary
 u              res     1       ; general temporary (another)