; ==== ISUAL Flight Software -- Univ of California, Berkeley, SSL ====
; EXECUTE.A -- Execute Ground Commands
; Entry point "EXECUTE" is passed HL = address of a command
;   returns A = result code (see below)
;
; For some commands, a call is made to an entry point
; in EEPROM (EE_EXEC2 in EEPROM.A)
;
; Revision History:
;  18-Dec-2002 - SPG - ISUAL Flight Software rev 7.3
;    First Official Release
;  31-Dec-2002
;    Eliminated some error symbols
;    Added I_NOP
;   7-Feb-2003 - SPG 
;    In I_SOH_NOMINAL/REDUNDANT,  don't set SCIF_CTL_O bits 4..7
;  18-Feb-2003 - SPG   (Rev 7.7)
;    make I_DELAY use GBL_SECONDS_CTR
;    implement I_SP_TIMED_STIM
;      and       I_TRIGGER_DELAY_SET
;    I_STANDBY doesn't turn off camera
;  7-Mar-2003
;    Eliminate I_TLM_FLUSH
; 11-Mar-2003
;    Capture Camera N pretrig in SOH+141
; 19-May-2003
;    restored I_TLM_FLUSH (with software switch)
; 29-May-2003
;    changed CCSDS_SEND calls to CCSDS_HSKP     
;    moved to EEPROM: I_CAM, I_SPF, I_AP, I_TLM_FLUSH
; 6-Aug-2003
;    allow non-time-tagged exec of HV_VAL_SETM and HV_COUNT_SET
;    restore I_TLM_FLUSH
;    correct write_eeprom_page
;    MMCB_FORMAT checks for DCM and TM queues empty and standby mode
; 8-Aug-2003
;    moved I_GENERIC_CMD and I_TLM_FLUSH to EEPROM
; 9-Aug-2003
;    MMCB_FORMAT sets MODE, ignores multiple calls
; 17-Aug-2003
; for I_TRIGGER_ENABLE, disable call to MMCB_INITEVQ
;  9-Sep-2003
;  moved I_CAM_HV_ON, I_SPA_HV_ON, I_SPB_HV_ON
;  17-Sep-2003
;  fix bug in I_STANDBY which could turn on a heater
;  19-Sep-2003
;   Change I_DCM_OFF to clear the time-tagged list
;  25-Sep-2003 -- correct handling of 
;   invalid service in I_PWR_ON
;  23-June-2004 -- pick up SPF trigger channel for telemetry
        include execute.i
        include ioports.i
        include util.i
        include cmd.i
        include dcm.i
        include gbl.i
        include ccsds.i
        include cdi.i
        include task.i
        include mmcb.i
        include sc.i
        include pvcf.i
        include pwr.i
        include clock.i
        include mm.i
        include htr.i
        include filter.i
        include debug.i
        include eeprom.i

; Result codes
; 0                ; OK
; FE               ; bad checksum
; FD               ; bad ApID
;ERR_PARAMVAL equ 1 ; bad parameter value
;ERR_BADOP    equ 2 ; bad opcode
;ERR_TTFULL   equ 3 ; time-tagged list is full
;ERR_DONE     equ 5 ; Requested Operation already done
;ERR_NEED     equ 6 ; Need to do a prior operation
;ERR_HV       equ 7 ; Violates HV setting rules
;ERR_ABORT    equ 8 ; failed a Verify
;ERR_TIMEOUT  equ 9 ; Timeout of a Wait
;ERR_SEQ      equ 10 ; Sequence Number not as expected
;ERR_CHKS     equ 11  ; Error checksum in bank
;ERR_CHKR     equ 12  ; Error wrong Revision in bank


; HL = addr of TASK
EXECUTE_INIT:

; set 25 seconds as default timeout
;  on "wait" commands
        mvi a,25
        sta GBL_WAIT_timeout
; zero packet sequence counters
        lxi h,0
        shld sq09
        shld sq1A
        shld sq1B
        ret

EXECUTE:
        push b
        push d
        push h

; HL points to opcode of command
; C =0 if command was immediate, =1 from time-tagged list
        mov a,M         ; opcode
; move pointer past the opcode and sequence number
        inx h
        inx h
; interpret the Opcode
        cpi 020h ; I_NOP
         jz inop
        cpi 009h ;  I_DCM_ON
         jz dcm_on
        cpi 00Ah ;  I_DCM_OFF
         jz dcm_off
        cpi 021h ;  I_IN
         jz io_in
        cpi 022h ;  I_OUT
         jz io_out
        cpi 05Ch ;  I_SPS
         jz isps
        cpi 01Eh ;  I_MEMDUMP
         jz memdump
        cpi 04Ah ;  I_PATCH1
         jz patch1
        cpi 04Bh ;  I_PATCH2
         jz patch2
        cpi 04Ch ;  I_PATCH4
         jz patch4
        cpi 01h  ;  I_RUN
         jz run
        cpi 03Eh ;  I_STANDBY
         jz standby
        cpi 06h ;   I_SAFE
         jz safe
        cpi 03Ch ;  I_MMCB_FORMAT
         jz do_mmcb_format
        cpi 03Fh ;  I_TM_FORMAT
         jz do_tm_format
        cpi 02h  ;  I_PWR_ON
         jz pwr_on
        cpi 03h  ;  I_PWR_OFF
         jz pwr_off
        cpi 07h  ;  I_MM_ON
         jz do_mm_on
        cpi 08h  ;  I_MM_OFF
         jz do_mm_off
        cpi 046h ;  I_V4_SET
         jz v4_set
        cpi 047h ;  I_TIMESET
         jz timeset
        cpi 048h ; I_TRIGGER_DELAY_SET
         jz trigger_delay_set
        cpi 049h ;  I_TIMED_STIM
         jz timed_stim
        cpi 023h ;  I_CDI
         jz cdi
        cpi 076h ;  I_HV_VAL_SET1
         jz hv_val_set1
        cpi 077h ;  I_HV_VAL_SETM
         jz hv_val_setm
        cpi 078h ;  I_HV_COUNT_SET
         jz hv_count_set
        cpi 054h ;  I_DELAY
         jz delay
        cpi 05Ah ;  I_TLM_NOMINAL
         jz tlm_nominal
        cpi 05Bh ;  I_TLM_REDUNDANT
         jz tlm_redundant
        cpi 060h ;  I_SOH_NOMINAL
         jz soh_nominal
        cpi 061h ;  I_SOH_REDUNDANT
         jz soh_redundant
        cpi 064h ;  I_PPS_NOMINAL
         jz pps_nominal
        cpi 065h ;  I_PPS_REDUNDANT
         jz pps_redundant
        cpi 05Fh ;  I_HEATER
         jz heater
        cpi 066h ;  I_FW_MOTOR_ON
         jz fw_motor_on
        cpi 067h ;  I_FW_MOTOR_OFF
         jz fw_motor_off
        cpi 039h ;  I_FILTER_SET
         jz filt_set
        cpi 062h ;  I_FILTER_RESYNC
         jz filt_resync
        cpi 068h ;  I_MM_DUMP
         jz mm_dump
        cpi 06Bh ;  I_AP_NOMINAL
         jz ap_nominal
        cpi 06Ch ;  I_AP_REDUNDANT
         jz ap_redundant
        cpi 06Dh ;  I_AP_PWR_ON
         jz ap_pwr_on
        cpi 06Eh ;  I_AP_PWR_OFF
         jz ap_pwr_off
        cpi 072h ;  I_XGROUP
         jz xgroup
        cpi 06Fh ;  I_BEGIN_GROUP
         jz begin_group
        cpi 070h ;  I_END_GROUP
         jz end_group
        cpi 06Ah ;  I_TO_EEPROM
         jz to_eeprom
        cpi 071h ;  I_CHECKSUM
         jz checksum
        cpi 073h ;  I_BEGIN_DSP
         jz begin_dsp
        cpi 074h ;  I_DSP
         jz do_dsp
        cpi 075h ;  I_EEPROM_TO_MM
         jz eeprom_to_mm
        cpi 079h ;  I_LOAD_DCM
         jz load_dcm
        cpi 07Ah ;  I_TRIGGER_SETUP
         jz tsu
        cpi 07Bh ;  I_TRIGGER_ENABLE
         jz tebl
        cpi 07Ch ;  I_TRIGGER_DISABLE
         jz tdis
        cpi 07Dh ;  I_SP_PWR_ON
         jz sp_pwr_on
        cpi 07Eh ;  I_SP_PWR_OFF
         jz sp_pwr_off
        cpi 026h ; I_CAM_PWR_ON
         jz cam_pwr_on
        cpi 027h ;  I_CAM_PWR_OFF
         jz cam_pwr_off
        cpi 069h ; I_STOP
         jz stop
        cpi 044h ; I_SIM_AP_TRIGGER
         jz sim_ap_trigger
        cpi 081h ; I_X1PVCF
         jz x1pvcf
        cpi 082h ; I_DAY1_THR_SET
         jz dayth1
        cpi 083h ; I_DAY2_THR_SET
         jz dayth2
        cpi 084h ; I_CHK
         jz chk
        cpi 08Fh ; I_TTLIST_DUMP
         jz ttd

; go to "EXEC2" (in EEPROM) for more commands
        push psw
        mvi a,ee_bank
        out BANK_SELECT_O
        pop psw
        call ee_exec2
        cpi 0
        jz exitok
        cpi 2 ; ERR_BADOP    ; result code: invalid opcode
        jz badop
        jmp exit
badop:  lxi h,GBL_SOH+106   ; increment counter
        inr M
        
exit:   pop h
        pop d
        pop b

        ret


; Successful command execution
exitok: mvi a,0          ; result code=0 (OK)
        lxi h,GBL_SOH+51 ; cmds successfully executed
        call INCBIG
; record the time of last command
        lxi h,GBL_SOH+53
        call clock_read
        lxi d,GBL_SOH+53
        call clock_6_to_10
        jmp exit


; command with bad argument values
badval: mvi a,1 ; ERR_PARAMVAL
        lxi h,GBL_SOH+50
        inr M
        jmp exit

badp:   mvi a,1 ; ERR_PARAMVAL
        jmp exit

; command violates HV setting rules
badhv:  mvi a,7 ; ERR_HV
        jmp exit

; I_IN port=X
io_in:
        mov a,M         ; port
        sta in_c+1      ; modify instruction
in_c:   in 0            ; (this gets modified)
in_c1:  sta in_data
        sta GBL_SOH+13  ; put in housekeeping too
; make a special packet to send the result
        mvi a,1Ah       ; ApID = 71A
        lxi b,20        ; total packet length
        lhld sq1A       ; this ApID's source sequence number
        xchg    
        lxi h,in_data   ; point to data
        call CCSDS_HSKP ; generate CCSDS and send it out
        lhld sq1A
        inx h
        shld sq1A
        jmp exitok
sq1A    ds 2
in_data ds 1

; I_OUT port=X data=X
io_out:
        mov a,M         ; port
        sta out_c+1     ; modify instruction
        inx h
        mov a,M         ; data
out_c:  out 0           ; (this gets modified)
        jmp exitok


; I_CDI
; Generic CDI command
sq1b    ds 2
cdirv   ds 2   ; returned value
cdi:    mov a,M         : CDI Opcode
        ani 0F0h
        cpi 0E0h        ; a "read" command?
        jnz sendd       ; no, just a send
; send, expecting a response
rback:  mov a,M         ; opcode  
        lxi h,cdirv     ; where to store response (2 bytes)
        call CDI_READBACK
; send 71B packet -- CDI readback
x71B:   mvi a,1Bh       ; ApID 71B
        lxi b,20        ; total packet length is 20
        lhld sq1B       ; this ApID's source sequence number
        xchg    
        lxi h,cdirv     ; data
        call CCSDS_HSKP  ; send it out
; increment the source sequence count
        lhld sq1B
        inx h
        shld sq1B
        jmp exitok

; ordinary "send"
sendd:  mov a,M         ; opcode
        inx h           ; point to CDI data (2 bytes)
        call CDI_SEND

; Capture any parameters being set
        lxi d,GBL_SOH+94  ; IDH_C_EXP
        cpi IM_EXP_DUR  ; camera exposure duration
        jz setparm2     ; store 2 bytes
        lxi d,GBL_SOH+220
        cpi IM_GATE_DLY ; IDH_GATEDELAY
        jz setparm2
        lxi d,GBL_SOH+240
        cpi IM_REP_PER  ; IDH_CAM_I_INT
        jz setparm2
        lxi d,GBL_SOH+141 ; *** 11-mar-2003 - was 104 
        cpi IM_PRE_TRIG ; IDH_N_CPRE
        jz setparm1
        lxi d,GBL_SOH+93
        cpi IM_POST_TRIG ; IDH_N_CPOST
        jz setparm1
        lxi d,GBL_SOH+222
        cpi IM_GOFF_ENBL ; IDH_GATE_NOFF
        jz setparm1
        lxi d,GBL_SOH+239
        cpi IM_TRIG_LKOUT ; IDH_N_ELOCK
        jz setparm1
        lxi d,GBL_SOH+159 ; IDH_AP_NPOST
        cpi MM_AP_PT_N
        jz setparm2
        lxi d,GBL_SOH+153 ; IDH_SPF_NPOST
        cpi MM_SPF_PT_N
        jz setparm2
; no parameters set by this CDI
        jmp exitok

setparm2:   ; store a 2-byte parameter
        mov a,M
        stax d
        inx d
setparm1:   ; store a 1-byte parameter
        inx h
        mov a,M
        stax d
        jmp exitok


; I_SPS ENABLE=X RATE=X
; Activate/Deactivate Slow-rate Spectrophotometer data taking
isps:   mov a,M
        cpi 0           ; 0=disable
        jz sps_d
; enable SPS
        lda GBL_SOH+11
        ori 02h         ; lite bit 1
        sta GBL_SOH+11
        inx h
        mov a,M         ; RATE
        cpi 0
        jz sps_16       ; 0=slow, 1=fast
; always set b0=1 to enable slow SPS accum
; set b1=1 for 0.8s (fast) accum
        lda GBL_IDC_CTRL+1
        ori 03h         ; b1=1 b0=1
        sta GBL_IDC_CTRL+1
        jmp xscdi
; set b1=0 for 1.6s (slow) accum
sps_16: lda GBL_IDC_CTRL+1
        ori 01h         ; b0=1
        ani 0FDh        ; b1=0
        sta GBL_IDC_CTRL+1
xscdi:  mvi a,IDC_CTRL
        lxi h,GBL_IDC_CTRL
        call cdi_send
        jmp exitok

; disable SPS
sps_d:  lda GBL_SOH+11
        ani 0FCh         ; b1=0 b0=0
        sta GBL_SOH+11
        jmp xscdi


; I_MEMDUMP ID=X BANK=XX ADDR=XXX
memdump:
; build packet data in GBL_TEMP
        lxi d,GBL_TEMP
        mov a,M         ; ID
        stax d
        inx h           
        inx d
; Note: 2-byte BANK retained for compatibility
; with older command procedures.
; BANK value is one byte
         mov a,M         ; Bank
        stax d
        mov b,a
        inx h
        inx d
        mov a,M
        stax d
        mov c,a         ; BC=Bank (B ignored)
        inx h
        inx d
; save current Bank setting
        in BANK_SELECT_I
        push psw
; set bank to be dumped
        mov a,c         
        out BANK_SELECT_O
; make HL = dump address
        mov a,M         ; address high
        stax d
        mov b,a
        inx h
        inx d
        mov a,M         ; address low
        stax d
        inx d
        mov h,b
        mov l,a         ; HL points to data to be dumped
        mvi c,128       ; always dump 128 bytes
        call COPY_BYTES ; (DE already pointed to destination)
; restore Bank register
        pop psw
        out BANK_SELECT_O
; GBL_TEMP data is built.
; Now generate the Dump packet
        mvi a,09h       ; ApID = 709
        lxi b,152       ; total packet length
        lhld sq09       ; this ApID's source sequence number
        xchg            ; in DE
        lxi h,GBL_TEMP  ; point to data
        call CCSDS_HSKP ; generate CCSDS and send it out
        lhld sq09
        inx h
        shld sq09
        jmp exitok
sq09    ds 2

        


; I_PATCH1 BANK=x ADDR=xx DATA=X
patch1:
; preserve original Bank
        in BANK_SELECT_I
        push psw        ; low
; set new BANK
        mov a,M         
        out BANK_SELECT_O
        inx h
; get ADDR
        mov d,M
        inx h
        mov e,M
; point to data
        inx h           
; Store the bytes
; HL - points to patch bytes in command packet
; DE - points to where bytes should be stored
        mvi c,1         ; just 1 byte
        jmp store

; I_PATCH2 BANK=x ADDR=xx DATA=XX
patch2:
; preserve original Bank
        in BANK_SELECT_I
        push psw        
; set new BANK
        mov a,M         
        out BANK_SELECT_O
        inx h
; get ADDR
        mov d,M
        inx h
        mov e,M
; point to data
        inx h  
; Store the bytes
; HL - points to patch bytes in command packet
; DE - points to where bytes should be stored
        mvi c,2         ; 2 bytes
        jmp store

; I_PATCH4 BANK=x ADDR=xx DATA=xxxx
patch4:
; preserve original Bank
        in BANK_SELECT_I
        push psw 
; set new BANK
        mov a,M  
        out BANK_SELECT_O
        inx h
; get ADDR
        mov d,M
        inx h
        mov e,M         ; DE=ADDR
; point to data
        inx h 
; Store the bytes
; HL - points to patch bytes in command packet
; DE - points to where bytes should be stored
        mvi c,4         ; store 4 bytes
        jmp store

; HL - points to patch bytes in command packet
; DE - points to where bytes should be stored
; C  - number of bytes to store
store:  mov a,M         ; byte from command
        stax d          ; store where it goes
; next byte
        inx h           ; advance pointers
        inx d
        dcr c           ; decrement count
        jnz store       ;  until zero
; restore original Bank
        pop psw
        out BANK_SELECT_O
        jmp exitok


; I_STANDBY
standby: 
; Turn off HV power services 
        mvi a,9         ; camera HV
        call pwr_set_off
        mvi a,10        ; SP 1..3
        call pwr_set_off
        mvi a,11        ; SP 4..6
        call pwr_set_off
        lxi h,0
        mvi a,AP_HV_OFF_A
        call cdi_ahl
        mvi a,AP_HV_OFF_B
        call cdi_ahl

; Terminate Camera and Photometer data taking
        mvi a,0
        sta GBL_SOH+11          ; stop packet generation
        lxi h,0
        mvi a,MM_IM_ENBL        ; stop hardware readouts
        call cdi_ahl
        mvi a,MM_SPF_ENBL
        call cdi_ahl
        mvi a,MM_SPS_ENBL
        call cdi_ahl
        mvi a,MM_AP_ENBL
        call cdi_ahl

; deactivate 5 heaters
        mvi a,1
        mvi b,0         ; 0=deactivate
        call HTR_SET
        inr a  ; 2
        call HTR_SET
        inr a  ; 3
        call HTR_SET
        inr a  ; 4
        call HTR_SET
        inr a  ; 5
        call HTR_SET

; Turn off other power services 
        mvi a,13        ; stepper motor
        call pwr_set_off
        mvi a,8         ; image front lens heater
        call pwr_set_off
        mvi a,4         ; imager FEC (daylight sensor)
        call pwr_set_off
        mvi a,3         ; TEC   
        call pwr_set_off
; leave MM(0) and DCM(1) on

; Activate IDC Reset before turning off SP or AP
        mvi a,0
        out IDC_RESET_O
        call sp_off
        call ap_off

; turn off the IDC
        mvi a,2         ; IDC   
        call pwr_set_off

; set Standby mode
        mvi a,mode_Standby
        sta GBL_SCIENCE_MODE

        jmp exitok

; I_STOP
stop:
; Terminate Camera and Photometer data taking
        mvi a,0
        sta GBL_SOH+11          ; stop readout processing
        lxi h,0
        mvi a,MM_IM_ENBL        ; stop hardware readouts
        call cdi_ahl
        mvi a,MM_SPF_ENBL
        call cdi_ahl
        mvi a,MM_SPS_ENBL
        call cdi_ahl
        mvi a,MM_AP_ENBL
        call cdi_ahl
        jmp exitok

; I_SAFE
safe:   mvi a,1         
; stop exec time-tagged commands
        sta GBL_TT_ABORT
; Stop science data generation
        mvi a,0
        sta GBL_TM_STATUS
        jmp standby

; I_MMCB_FORMAT MODE=X
; allocate MMCBs and readout buffers
do_mmcb_format:
; Make sure in standby mode and queues are idle
;        lda GBL_SCIENCE_MODE
; mvi c,1        ; (for debug display -- tells why command failed)
;        cpi MODE_STANDBY
;        jnz need
 mvi c,2
        lda GBL_DCM_IDLE
        cpi 1
        jnz need
 mvi c,3
        lda GBL_TM_IDLE
        cpi 1
        jnz need
proceed:  
; are MMCB parameters defined (patched-in) ?
 mvi c,4
        lda GBL_CAM_NWB
        cpi 0EFh        ; (1st byte of actual value won't ever be EF)
        jz need          ; no
; format the MMCB queues
        call MMCB_FORMAT
        mov a,M         ; MODE=X
        sta GBL_SCIENCE_MODE
        jmp exitok

already_done:
        mvi a,5 ; ERR_DONE
        jmp exit

; need to do a prior operation
need:   mov a,c
        cpi 0
        cnz debug_showa
        mvi a,6 ; ERR_NEED
        jmp exit

; I_TM_FORMAT -- allocate the Spacecraft TM Buffers
do_tm_format:
        lda GBL_TM_IDLE
        cpi 1
        jnz need  ; need to stop TM task 
        lda GBL_MM_Status
        cpi 1
        jnz need  ; need to turn on MM
; need to have run DCM_SETUP
        lda GBL_DCM_STATUS
        cpi 0FFh        ; DCM not initialized
        jz need 
; Initialize PVCF generation
        call PVCF_START
; set TM active
        mvi a,1
        sta GBL_TM_STATUS
        jmp exitok

; I_PWR_ON service=x
pwr_on: mov a,M         ; get service number
        call PWR_SET_ON ; set power service on
        cpi 0
        jz badp         ; service number was invalid
        jmp exitok


; I_PWR_OFF service=x
pwr_off: mov a,M        ; get service number
        call pwr_set_off ; set power service off
        cpi 0FFh 
        jz badp         ; service number was invalid
        jmp exitok


; I_V4_SET code=X
v4_set: mov a,M         ; get code
        cpi 0 
        jz v4_0
        cpi 1
        jnz badval
        in HV_STS_I
        ori 4           ; b2=1
        out HV_CTL_O
        jmp exitok
v4_0:   in HV_STS_I
        ani 0FBh        ; b2=0
        out HV_CTL_O
        jmp exitok

; I_TIMESET 
; Enable spacecraft time-set
timeset:
; enable SC Time-set
        mvi a,1
        sta GBL_TEST
; GBL_TEST will be reset to 0
; after a successful timeset
;
; clear Time Fault
        mvi a,0
        sta GBL_SOH+30
        jmp exitok

;-----------------------------------------------------------------
; FUNCTION:  HV_VAL_SET1
; PURPOSE:   Set a single HV register
; REGS INP:  HL=&HVID,VAL  C=time-tagged command flag
; REGS OUT:  A=result code  BC,DE,HL=trash
; PSW OUT:   
;
; NOTES:     Assumes HV is unlocked and value does not exceed max.  
;            Sets HV count to 1.  If HVPS is on, it stays on.
;-----------------------------------------------------------------

; v8  Add comments.  Add HV error bit clear/check.  Add HVID check.
; v8  CAI 2002-09-12
; I_HV_VAL_SET1 HVID=X VAL=X
; Set single HV register

hv_val_set1:
        mov a,c        
        cpi 1           ; time-tagged?
        jz badhv        ; should not be
; check for valid HVID
        mov a,M         ; HVID
        call hvid_chk   ; check HVID 
        cpi 0FFh
        jz badval       ; if bad HVID
; Set hv write COUNT=1
        mvi a,0Fh       ; clear HV error bits 
        out HVERR_CLR_O 
        mvi a,1
        out HV_CNTR_O
        inx h
        mov a,M         ; VAL
; hvid_chk returned DE = addr of output routine
        xchg            ; HL=&output routine
        call gothere    ; call output routine
        in HVERR_STS_I  
        ani 0Fh         ; check HV error bits 
        jnz badhv       ; if errors 
        jmp exitok
;
gothere: pchl


;-----------------------------------------------------------------
; FUNCTION:  HV_COUNT_SET
; PURPOSE:   Set HV write counter register
; REGS INP:  HL=&COUNT  C=time-tagged command flag
; REGS OUT:  A,BC,DE,HL=trash
; PSW OUT:   Error if count <2
;
; NOTES:     Assumes HV is unlocked.  Expects count 2-255.
;            No error return if HV is locked.
;-----------------------------------------------------------------

; I_HV_COUNT_SET COUNT=X
hv_count_set:
;***6-Aug-03
;***        mov a,c        
;***        cpi 1           ; time-tagged?
;***        jnz badhv       ; should be
;
        mvi a,0Fh       ; clear HV error bits 
        out HVERR_CLR_O 
        mov a,M         ; COUNT
; must have COUNT>1
        cpi 2
        jm badval       ; if A < 2  
; set count register
        out HV_CNTR_O
        in HVERR_STS_I  
        ani 0Fh         ; check HV error bits 
        jnz badhv       ; if errors
        jmp exitok


;-----------------------------------------------------------------
; FUNCTION:  HV_VAL_SETM
; PURPOSE:   Set one of several HV registers
; REGS INP:  HL=&HVID,VAL  C=time-tagged command flag
; REGS OUT:  A=result code  BC,DE,HL=trash
; PSW OUT:   
;
; NOTES:     Assumes HV is unlocked and value does not exceed max.  
;            Assumes HV count is non-zero.  Turns HVPS off.
;-----------------------------------------------------------------

hv_val_setm:
;***6-Aug-03
;***        mov a,c        
;***        cpi 1           ; time-tagged?
;***        jnz badhv       ; it should be
        mov a,M         ; HVID
        call hvid_chk   ; check HVID  
        cpi 0FFh
        jz badval       ; if bad HVID
; turn off HV power supply for this HVID
        mvi b,9         ; PS9 is HVPS for camera
        ani 0F0h        ; A=HVID
        jz setoff
        mvi b,10        ; PS10 is HVPS for SP 1-3
        cpi 10h
        jz setoff
        mvi b,11        ; PS11 is HVPS for SP 4-6
        cpi 20h
        jz setoff
        jmp badval      ; if bad HVID (not 0x,1x,2x)
setoff: mov a,b         ; PS
        call pwr_set_off
;
; v8: Insert delay after power-off?  CAI 2002-09-13
; ***
        mvi a,0Fh       ; clear HV error bits v8
        out HVERR_CLR_O 
; now set the HV value in an HV register
        inx h           
        mov a,M         ; VAL
        xchg            ; HL=&output routine
        call gothere    ; call output routine
        in HVERR_STS_I  ; 
        ani 0Fh       ; check HV error bits 
        jnz badhv       ; if errors 
        jmp exitok

;-----------------------------------------------------------------
; FUNCTION:  HVID_CHK                                           
; PURPOSE:   Check for valid HV ID number & get jump address
; REGS INP:  A=HVID
; REGS OUT:  DE=&output routine  A=HVID or FF if error
; PSW OUT:   
;
; NOTES:     Error if HV ID not found in table HVTAB
;-----------------------------------------------------------------

hvid_chk:
        push h          ; save HL
        mov e,a         ; save HVID
        lxi h,hvtab
hvts:   mov a,M
        cpi 0FFh        ; end of table?
        jz hi_ret       ; if so, error exit
        cmp e           ; HVID match?
        jz hvi_ok       ; if match
        inx h           ; check next entry
        inx h
        inx h
        jmp hvts
hvi_ok: inx h           ; got valid match
        mov a,e         ; restore HVID
        mov e,M
        inx h
        mov d,M         ; DE=&output routine
hi_ret: pop h           ; restore &HVID
        ret             ; A=0FFh if invalid ID


hvtab   db 00h          ; Dispatch table for ...
         dw cpday       ;  HV register output routines
        db 01h          ; HV ID code
         dw cpnight     ;  Output routine address
        db 0Ah          ; 
         dw cpmax

        db 02h
         dw cmday
        db 03h
         dw cmnight1
        db 04h
         dw cmnight2
        db 05h
         dw cmnight3
        db 06h
         dw cmnight4
        db 07h
         dw cmnight5
        db 08h
         dw cmnight6
        db 09h
         dw cmnight7
        db 0Bh
         dw cmmax

        db 10h
         dw sp1_day
        db 11h
         dw sp1_aur
        db 12h
         dw sp1_spr
        db 13h
         dw sp2_day
        db 14h
         dw sp2_aur
        db 15h
         dw sp2_spr
        db 16h
         dw sp3_day
        db 17h
         dw sp3_aur
        db 18h
         dw sp3_spr
        db 20h
         dw sp4_day
        db 21h
         dw sp4_aur
        db 22h
         dw sp4_spr
        db 23h
         dw sp5_day
        db 24h
         dw sp5_aur
        db 25h
         dw sp5_spr
        db 26h
         dw sp6_day
        db 27h
         dw sp6_aur
        db 28h
         dw sp6_spr

        db 0FFh       ; must be last entry in table
; FF marks the end of the table for the search.


; HV Output Routines

cpday:  out PHOS_DAY_O
        ret
cpnight: out PHOS_SPR_AUR_O
        ret
cpmax:  out PHOS_MAX_O
        ret

cmday:  out MCP_DAY_O
        ret
cmnight1: out MCP_NITE_1_O
        ret
cmnight2: out MCP_NITE_2_O
        ret
cmnight3: out MCP_NITE_3_O
        ret
cmnight4: out MCP_NITE_4_O
        ret
cmnight5: out MCP_NITE_5_O
        ret
cmnight6: out MCP_NITE_6_O
        ret
cmnight7: out MCP_NITE_7_O
        ret
cmmax:  out MCP_MAX_O
        ret

sp1_day: out SP1_DAY_O
        ret
sp1_spr: out SP1_SPR_O
        ret
sp1_aur: out SP1_AUR_O
        ret
sp2_day: out SP2_DAY_O
        ret
sp2_spr: out SP2_SPR_O
        ret
sp2_aur: out SP2_AUR_O
        ret
sp3_day: out SP3_DAY_O
        ret
sp3_spr: out SP3_SPR_O
        ret
sp3_aur: out SP3_AUR_O
        ret
sp4_day: out SP4_DAY_O
        ret
sp4_spr: out SP4_SPR_O
        ret
sp4_aur: out SP4_AUR_O
        ret
sp5_day: out SP5_DAY_O
        ret
sp5_spr: out SP5_SPR_O
        ret
sp5_aur: out SP5_AUR_O
        ret
sp6_day: out SP6_DAY_O
        ret
sp6_spr: out SP6_SPR_O
        ret
sp6_aur: out SP6_AUR_O
        ret

; I_DELAY seconds=X
; delay command processing for up to 60 seconds
delay:  
; get number of seconds to delay
        mov a,M         ; seconds (from command data)
        cpi 61
        jp badp         ; limit to 60
        mov c,a         ; C=seconds
; If Trigger interrupt is not enabled, use the
; down-counter timer; otherwise, use GBL_SECONDS_CTR
        in IRQ_ENABLE_I
        ani 40h
        jnz use_seconds ; trigger is enabled
 jmp use_seconds

; use down-counter
; Multiply C by 1024
        lxi h,1024
        lxi d,1024
dl0:    dcr c
        jz dl1
        dad d
        jmp dl0
; Set down-counter timer
        public DCT_SET
dl1:    call DCT_SET
; wait for timer to expire
dl2:    call task
        lda GBL_DCTIMER
        cpi 1
        jnz dl2
        jmp exitok

use_seconds:
        lda GBL_SECONDS_CTR
        mov b,a         ; B=starting seconds value
dloop:  call task
        lda GBL_SECONDS_CTR
        sub b           ; A=elapsed seconds
        sub c           ; subtract delay
        ani 80h         ; negative result?
        jnz dloop       ; yes, keep delaying
        jmp exitok


; I_MM_ON
do_mm_on:
        call MM_ON
        jmp exitok

; I_MM_OFF
do_mm_off: 
        call MM_OFF
        jmp exitok

p_result  ds 2


; I_DCM_ON
dcm_on:
; Mass Memory must be on 
        lda GBL_MM_STATUS
        cpi 1 
        jnz need
; ignore if DCM disabled
        lda GBL_DCM_STATUS
        cpi 0FBh
        jz exitok
; In case DCM was already running,
; force DCM task to re-initialize
; Activate DCM reset
        in MM_IM_DCM_STS_I
        ori 040h        ; turn on b6
        out MM_IM_DCM_CTL_O
; turn off DCM power
        mvi a,1
        call PWR_SET_OFF
; DCM now inactive
        mvi a,0FFh
        sta GBL_DCM_STATUS
; delay and let DCM task re-initialize
        call task
; turn on DCM power
        mvi a,1
        call PWR_SET_ON
; 10 ms wait 
        mvi c,100
wwx:    call wait_1ms
        dcr c
        jnz wwx
; release DCM reset
        in MM_IM_DCM_STS_I
        ani 0BFh        ; turn off b6
        out MM_IM_DCM_CTL_O
; set DCM_STATUS=01h
        mvi a,01h                 
        sta GBL_DCM_STATUS
        jmp exitok

; I_DCM_OFF
dcm_off:
TTBANK  equ 3 
; clear Time-Tagged Command List
        mvi a,TTBANK    ; Time-Tagged Bank
        out BANK_SELECT_O ; set bank register
        lxi h,4000h     ; first byte in banked memory
        mvi M,0FFh      ; mark end of list
        jmp exitok



; Commands to set Nominal or redundant telemetry channel

; I_TLM_NOMINAL
tlm_nominal:
        lda GBL_SCIENCE_MODE
        cpi 0           ; must be in Standby Mode
        jnz need        ; Need to change mode
; switch to nominal link
        in SCIF_STS_I
        ani 00Dh        ; bit 1 is off; 4..7 are zero
        out SCIF_CTL_O
        mvi a,0
        sta GBL_TLM_CHANNEL
        jmp exitok

; I_TLM_REDUNDANT
tlm_redundant:
        lda GBL_SCIENCE_MODE
        cpi 0           ; must be in Standby Mode
        jnz need        ; Need to change mode
; switch to redundant link
        in SCIF_STS_I
        ani 0Fh         l 4..7 off
        ori 02h         ; bit 1 is ON
        out SCIF_CTL_O
        mvi a,1
        sta GBL_TLM_CHANNEL
        jmp exitok

; make sure we are between SOH transmissions
ckilk:  mvi a,1         ; 1 = request SOH interlock
        sta GBL_TLM_ILK
; wait for SOH to be between SOH transmissions
wilk:   call task
        lda GBL_TLM_ILK
        cpi 2           ; 2 = interlock-set
        jnz wilk
; loop until XMTR is ready
loup:   in CMD_SOH_STS_I
        ani 1            ; bit 0: 1=Xmt buffer ready
        jnz rilk 
        call task       
        jmp loup
; release the interlock
rilk:   mvi a,0
        sta GBL_TLM_ILK
        ret

; I_SOH_NOMINAL
soh_nominal:
        lda GBL_SCIENCE_MODE
        cpi 0           ; must be in Standby Mode
        jnz need        ; Need to change mode
; make sure we are between SOH transmissions
        call ckilk
; now switch to nominal link
        in SCIF_STS_I
        ani 0Eh        ; bit 0  is off; bits 4..7 off
        out SCIF_CTL_O
        jmp exitok

; I_SOH_REDUNDANT
soh_redundant:
        lda GBL_SCIENCE_MODE
        cpi 0           ; must be in Standby Mode
        jnz need        ; Need to change mode
; make sure we are between SOH transmissions
        call ckilk
; now switch to redundant link
        in SCIF_STS_I
        ani 0Fh         ; zero bits 4..7 
        ori 01h         ; bit 0 is ON
        out SCIF_CTL_O
        jmp exitok


; I_HEATER ID=X ACTIVATE=X ON_SECS=X OFF_SECS=X
heater: mov a,M         ; ID
; ID must be 1..5
        cpi 0
        jz badp
        cpi 6
        jp badp
        inx h
        mov b,M         ; ACTIVATE
        inx h
        mov c,M         ; ON_SECS
        inx h
        mov d,M         ; OFF_SECS
        call HTR_SET
        jmp exitok

; I_FW_MOTOR_ON
fw_motor_on:
        call filter_motor_on
        jmp exitok

; I_FW_MOTOR_OFF
fw_motor_off:
        call filter_motor_off
        jmp exitok

; I_FILTER_RESYNC
filt_resync:
        call FILTER_RESYNC
        jmp exitok

; I_FILTER_SET CODE=X
filt_set:
        call filter_motor_on
        mov a,M         ; code
        cpi 0
        jz badp         ; must be 1..6
        cpi 7
        jp badp         ; >=7
        call FILTER_SET
        call filter_motor_off
        jmp exitok

; I_PPS_NOMINAL
pps_nominal:
        in SCIF_STS_I
        ani 00Bh        ; b2=0 4..7=0
        out SCIF_CTL_O
        jmp exitok

; I_PPS_REDUNDANT
pps_redundant:
        in SCIF_STS_I
        ani 0Fh         ; 4..7=0
        ori 04h        ; b2=1 00000100
        out SCIF_CTL_O
        jmp exitok

; I_MM_DUMP ID=X ADDR=XXXX
mm_dump:
; build packet data in GBL_TEMP
        mov a,M         ; ID
        sta GBL_TEMP
        inx h
        push h
; Note: 2-byte BANK retained for compatibility
; with older command procedures.
; BANK value is one byte
        mvi a,0
        sta GBL_TEMP+1
        mvi a,0F0h
        sta GBL_TEMP+2
; in dump packet, make Dump Address low 2 bytes of MM addr
        inx h
        inx h
        mvi c,2
        lxi d,GBL_TEMP+3
        call copy_bytes
; read MM into packet data area 
        xchg
        pop d           ; point to MM addr
        lxi b,128/4  ; words
        call MM_FETCH
; GBL_TEMP data is built.
; Now generate the Dump packet
        mvi a,09h       ; ApID = 709
        lxi b,152       ; total packet length
        lhld sq09       ; this ApID's source sequence number
        xchg            ; in DE
        lxi h,GBL_TEMP  ; point to data
        call CCSDS_HSKP ; generate CCSDS and send it out
        lhld sq09
        inx h
        shld sq09
        jmp exitok

; I_TO_EEPROM FROMBANK=X TOBANK=X
to_eeprom:  mov a,M
        sta source_bank
        inx h
        mov a,M
        sta target_bank

; Using page-writes of EEPROM (128 bytes)
; Copy source bank (RAM) to a target bank (EEPROM)

; last bytes of bank contain:
;  7FFC - revision code
;  7FFD - number of bytes checksummed (2 bytes)
;  7FFF - checksum

        lda source_bank
        out BANK_SELECT_O
        lxi h,7FFDh
        mov d,M
        inx h
        mov e,M
        xchg
        shld byte_count
; first, copy last page of bank
        lxi h,7F80h
        lxi d,GBL_128BYTES
        mvi c,128
        call copy_bytes
        lda target_bank
        lxi h,7F80h
        lxi d,GBL_128BYTES
        xchg 
        call write_eeprom_page

; now copy the defined data
        lxi h,4000h
        shld pointer

another_page:
        lda source_bank
        out BANK_SELECT_O       ; source bank
        lhld pointer
        lxi d,GBL_128BYTES      ; copy 128 bytes to RAM
        mvi c,128
        call copy_bytes
        lda target_bank
        lhld pointer
        lxi d,GBL_128BYTES      ; copy RAM to EEPROM
        xchg 
        call write_eeprom_page
; decrement count by one page
        lhld byte_count
        lxi d,-128
        dad d
        shld byte_count
        mov a,h
        ani 80h
        jnz exitok
; advance pointer by one page
        lhld pointer
        lxi d,128
        dad d
        shld pointer
        jmp another_page
        
byte_count  ds 2
pointer     ds 2
source_bank ds 1
target_bank ds 1

write_EEPROM_page:
; A - bank
; HL - points to source
; DE - points to first byte to write
        push psw
        push b
        push d
        push h
; save pointers
        push h  ; for write
        push d
; pacify watchdog
        out WATCHDOG_PET_O
; disable interrupts during copy
        di
; send EEPROM write-enable sequence
        push psw
        ani 0F0h        ; extract "y" bank 8,9,A,B or C

; bank=y1, addr=5555 data=AA
        inr a           ; y1
        out BANK_SELECT_O 
        lxi h,5555h
        mvi M,0AAh
; bank=y0, addr=6AAA data=55
        dcr a
        out BANK_SELECT_O 
        lxi h,6AAAh
        mvi M,055h
; bank=y1, addr=5555 data=A0
        inr a
        out BANK_SELECT_O 
        lxi h,5555h
        mvi M,0A0h
; bank=target
        pop psw
        out BANK_SELECT_O 
; copy 128 bytes
        pop h           ; store-addr
        pop d           ; source-addr
        mvi c,128       ; size of a page
l1:     ldax d
        mov M,a
        inx h
        inx d
        dcr c
        jnz l1
; wait 10 ms
        mvi c,11
l4:     call wait_1ms
        dcr c
        jnz l4
; enable interrupts again
        ei
        pop h
        pop d
        pop b
        pop psw
        ret

; subroutine to wait for power strobe busy to go down
waitpb: out WATCHDOG_PET_O
wpbl:   in HKP_STS_I
        ani 40h         ; test b6
        jnz wpbl
        ret

; I_AP_NOMINAL
ap_nominal:
        call waitpb     ; wait for power strobe busy to go down
        out AP_PWR_NOM_O  ; set AP to Nominal Power
        jmp exitok

; I_AP_REDUNDANT
ap_redundant:
        call waitpb     ; wait for power strobe busy to go down
        out AP_PWR_RED_O  ; set AP to Redundant Power
        jmp exitok


; I_BEGIN_GROUP BANK=X OFFSET=XX
begin_group:
        mov a,M         ; bank
        inx h
        mov d,M
        inx h
        mov e,M
        xchg            ; HL=offset
        call CMD_BEGIN_GROUP
        jmp exitok

; I_END_GROUP
end_group:
        call CMD_END_GROUP
        jmp exitok

; I_CHECKSUM BANK=X OFFSET=XX NBYTES=XX
checksum:
        mov a,M         ; BANK
        out BANK_SELECT_O
        inx h
        mov d,M         ; OFFSET
        inx h
        mov e,M
        inx h
        mov b,M         ; NBYTES
        inx h
        mov c,M
        lxi h,4000h
        dad d           ; HL = address
;
        mvi d,0         ; D accumulates the checksum 
        out WATCHDOG_PET_O
cksl:   mov a,d
        xra M           ; XOR byte
        mov d,a
        inx h
        dcx b
        mov a,b
        ora c           ; BC=0?
        jnz cksl
; telemeter the result in an I_IN packet
        mov a,d
        jmp in_c1

; I_XGROUP BANK=X OFFSET=XX
xgroup:
        mov a,M         ; BANK
        inx h
        mov d,M         ; OFFSET
        inx h
        mov e,M
        xchg
        call CMD_XGROUP
        jmp exitok

; I_BEGIN_DSP BANK=X OFFSET=XX
begin_dsp:
        mov a,M         ; BANK
        sta dsp_bank
        inx h
        mov d,M         ; OFFSET
        inx h
        mov e,M
        lxi h,4000h     ; base of banked memory
        dad d
        shld dsp_addr
        jmp exitok

dsp_bank ds 1
dsp_addr ds 2

; copy 6 bytes of DSP instruction into banked (RAM) memory
; I_DSP D=XXXXXX
do_dsp: lda dsp_bank
        out BANK_SELECT_O ; set bank
        xchg            ; DE points to XXXXXXX
        lhld dsp_addr   ; destination address
; DE=(source) HL=(destination)
        mvi c,6         ; copy 6 bytes
dodl:   ldax d          ; get source
        mov M,a         ; store 
        inx h           ; next
        inx d
        dcr c           ; count
        jnz dodl
; store updated address (incremented by 6)
        shld dsp_addr
        jmp exitok

; This is used to transfer DSP code from EEPROM to MM,
; ready to be copied by the DCM
; I_EEPROM_TO_MM BANK=X OFFSET=XX NWORDS=XX MM=XXXX
eeprom_to_mm:
        mov a,M         ; bank
        out BANK_SELECT_O  ; set EEPROM source bank
        inx h
        mov d,M         ; OFFSET=XX
        inx h
        mov e,M
        push d
        inx h           ; NWORDS=XX
        mov b,M
        inx h
        mov c,M
        push b
; copy MM address
        inx h           ; point to MM=
        mvi c,4
        lxi d,ee_MM
        call copy_bytes
; copy data from banked RAM to unbanked RAM
        pop h          ; NWORDS
        shld ee_nwords
        dad h
        dad h           ; x 4 -> number of bytes
        mov b,h
        mov c,l         ; BC = number of bytes
        pop h           ; OFFSET
        lxi d,4000h     ; base of banked RAM
        dad d           ; HL=source
        lxi d,GBL_DSP_BUF  ; DE=destination
; copy NBYTES bytes from EEPROM to unbanked RAM
cel2:   mov a,M
        stax d
        inx h
        inx d
        dcx b
        mov a,b
        ora c
        jnz cel2
; copy from unbanked RAM to MM
        lxi d,ee_mm       ; DE points to MM address
        lhld ee_nwords
        mov b,h
        mov c,l           ; BC=number of words
        lxi h,GBL_DSP_BUF ; HL=source pointer
        call mm_store
        jmp exitok
ee_nwords ds 2
ee_mm     ds 4

        
bpl_status ds 4

; I_LOAD_DCM
load_dcm:
        mvi a,4
        sta GBL_DCM_STATUS
; set BPL status=0
        lxi h,GBL_zero
        lxi d,GBL_BPL_STATUS
        lxi b,1
        call mm_store
; send DCM a CDI 31
        mvi a,31h
        call cdi_send
        lda GBL_SECONDS_CTR
        mov c,a
; wait for Busy=false
wbusy:  call task
        in MM_IM_DCM_STS_I
        ani 10h         ; bit 4: 1 -- busy=true
        jnz ckto
; then wait for BPL Status=1
        call task
        lxi h,bpl_status
        lxi d,GBL_BPL_STATUS
        push b
        lxi b,1
        call mm_fetch
        pop b
        lda bpl_status+3
        cpi 1
        jz dcm_loaded
; check timeout
ckto:   lda GBL_SECONDS_CTR
        sub c
        cpi 10           ; 10-second timeout
        jm wbusy
; timeout expired
        in MM_IM_DCM_STS_I
        mvi a,9 ; ERR_TIMEOUT
        jmp exit
dcm_loaded:
; show DCM Status of "6"
        mvi a,6
        sta GBL_DCM_STATUS
        jmp exitok


idc_on:
; turn IDC on if it's not already on
        in PWR_STS_LO_I                  
        ani 04h         ; b2
        rnz             ; IDC was already on
        mvi a,2         ; turn on power service 2
        call PWR_SET_ON
; 5-Nov2002 (Curt's latest instructions)
; 100 ms wait 
        mvi c,100
w10t:   call wait_1ms
        dcr c
        jnz w10t
; release IDC reset
        mvi a,80h
        out IDC_RESET_O
rbagain:
; Send CDI 4E 2877
; (sets SPS_SCALE123 and selects it for readback)
        mvi a,04Eh
        lxi h,2877h
        call CDI_AHL
; Readback SPS_SCALE123
        mvi a,0E7h
        lxi h,rback
        call CDI_READBACK
; If readback data is not 2877, repeat CDI sequence
        lda rback
        cpi 28h
        jnz rbagain
        lda rback+1
        cpi 77h
        jnz rbagain
; repeat current power command
        mvi a,2         ; turn on power service 2
        call PWR_SET_ON
; IDC is now in the mood to accept CDIs
; disable everything
        lxi h,0
        shld GBL_IDC_CTRL
; send the CDI
        lxi h,GBL_IDC_CTRL
        mvi a,IDC_CTRL
        call CDI_SEND
        ret

; I_TRIGGER_SETUP
tsu:
        in PWR_STS_LO_I                  
        ani 04h         ; b2
        jz need         ; reject if IDC not on
; IDC is on ...  command the the threshholds etc.
        mvi c,10
; setup lightning threshholds
; issue CDI commands 40..49
        lxi h,GBL_IDC_LTHRESH ; 10 16-bit words
; pick up trigger channel for telemetry
        mov a,M
        sta GBL_SOH+14  ; (science headers copy from here)
        mvi a,SP_LD_TH_A
idcl1:  call CDI_SEND
        inx h
        inx h
        inr a
        dcr c
        jnz idcl1
; Lightning Detect Control
        lxi h,GBL_IDC_LDETECT
        mvi a,SP_LD_CTRL
        call CDI_SEND
; select scaling for SPS
        lxi h,GBL_IDC_SPS_SCALE
        mvi a,SPS_SCALE123
        call CDI_SEND
        inx h
        inx h
        mvi a,SPS_SCALE456
        call CDI_SEND
        jmp exitok

; I_TRIGGER_ENABLE
tebl:
; don't allow unless IDC and SP both turned on
        in PWR_STS_LO_I                  
        ani 24h         ; b2 and b5
        cpi 24h
        jnz need
; Init Event queue pointers for each instrument
;****        call MMCB_INITEVQ

; If AP selected (I_AP enable=1),
; enable AP trigger
        lda GBL_SOH+11
        ani 01h
        jz notap
        lda GBL_IDC_CTRL
        ori 10h         ; b12=1
        sta GBL_IDC_CTRL
notap:
; if SPF selected,
; enable SP fast accumulation
        lda GBL_SOH+11
        ani 04h         ; b2 (SPF)
        jz notspf
        lda GBL_IDC_CTRL+1
        ori 05h         ; b2=1
        sta GBL_IDC_CTRL+1
notspf:
; if SPS selected,
; enable SP slow accumulation
        lda GBL_SOH+11
        ani 02h         ; b1 (SPS)
        jz notsps
        lda GBL_IDC_CTRL+1
; fast has to be on also
        ori 05h         ; b0,2=1
        sta GBL_IDC_CTRL+1
notsps:
; now enable MM/IM trigger
        lda GBL_IDC_CTRL
        ori 01h         ; b8=1
        sta GBL_IDC_CTRL
; enable DPU trigger
        lda GBL_IDC_CTRL+1
        ori 10h         ; b4=1
        sta GBL_IDC_CTRL+1
; send the CDI
        lxi h,GBL_IDC_CTRL
        mvi a,IDC_CTRL
        call CDI_SEND

; enable the Event (Trigger) interrupt - RST 6
        in IRQ_ENABLE_I
        ori 40h         ; b6=1 for RST6
        out IRQ_ENABLE_O

; Arm the IDC triggers
        call MMCB_REARM
        jmp exitok

; I_TRIGGER_DISABLE
tdis:
; disable Trigger interrupt (RST 6)
; and Exposure interrupt (RST 5)
        in IRQ_ENABLE_I
        ani 09Fh         ; b5,b6=0
        out IRQ_ENABLE_O
; disable MM and AP trigger (and set arm=0 too)
        lda GBL_IDC_CTRL
        ani 088h          ; b14,b10,b8,b9,b12,b13=0
        sta GBL_IDC_CTRL
; disable DPU trigger (and set arm=0) 
        lda GBL_IDC_CTRL+1
        ani 08Fh          ; b6,b5,b4=0
        sta GBL_IDC_CTRL+1
IDCCDI: lxi h,GBL_IDC_CTRL
        mvi a,IDC_CTRL
        call CDI_SEND
        jmp exitok

; I_SIM_AP_TRIGGER
sim_ap_trigger:
        lda GBL_IDC_CTRL
        ori 44h         ; b14=1 - Sim AP; b10=1 - Sim MM
        sta simap
        lda GBL_IDC_CTRL+1
        ori 40h         ; b6=1 - Sim DPU
        sta simap+1
        lxi h,simap
        mvi a,IDC_CTRL
        call CDI_SEND
        jmp IDCCDI
simap   ds 2

; I_SP_PWR_ON
sp_pwr_on:
; Turn on IDC if it's not already on
        call idc_on
; Turn on SP
        mvi a,5
        call PWR_SET_ON
; Enable fast and slow accumulation
        lda GBL_IDC_CTRL+1
        ori 05h         ; b0,b2=1
        sta GBL_IDC_CTRL+1
 ; (b2 set by I_SPS command)
        jmp IDCCDI

; I_SP_PWR_OFF
sp_pwr_off:
        call sp_off
        jmp exitok
sp_off:
; disable fast and slow accumulation
        lda GBL_IDC_CTRL+1
        ori 0FAh         ; b0,b2=0
        sta GBL_IDC_CTRL+1
; send the CDI
        lxi h,GBL_IDC_CTRL
        mvi a,IDC_CTRL
        call CDI_SEND
; now turn off the power service
        mvi a,5
        call PWR_SET_OFF
        ret

; I_AP_PWR_ON
ap_pwr_on:
; Make sure IDC is on 
        call idc_on
; wait for power strobe busy to go down
        call waitpb     
; set AP power on
        out AP_PWR_ON_O 
; Enable IDC outputs to the AP
        lda GBL_IDC_CTRL+1
        ori 08h         ; b3=1
        sta GBL_IDC_CTRL+1
; send the CDI
        jmp IDCCDI 

; I_AP_PWR_OFF
ap_pwr_off:
        call ap_off
        jmp exitok
ap_off:
; disable AP trigger
        lda GBL_IDC_CTRL
        ani 0EFh        ; b12=0
        sta GBL_IDC_CTRL
; disable IDC outputs to the AP
        lda GBL_IDC_CTRL+1
        ani 0F7h         ; b3=0 - disable IDC outputs to AP
        sta GBL_IDC_CTRL+1
; send the CDI
        lxi h,GBL_IDC_CTRL
        mvi a,IDC_CTRL
        call CDI_SEND
; wait for power strobe busy to go down
        call waitpb     
; set AP power off
        out AP_PWR_OFF_O 
        ret

; I_CAM_PWR_ON
cam_pwr_on:
        mvi a,4
        call pwr_set_on
; 200ms delay   (rev 7.3)
        mvi c,200
cpo1:   call wait_1ms
        dcr c
        jnz cpo1
        jmp exitok

; I_CAM_PWR_OFF
cam_pwr_off:
        mvi a,4
        call pwr_set_off
        jmp exitok

; I_DAY1_THR_SET VAL=X
dayth1: mov a,M         ; VAL
; must be 1..8E
        cpi 0
        jz badval
        ani 80h
        jz th1ok
        mov a,M
        ani 7Fh
        cpi 0Fh
        jp badval       ; >8E
th1ok:  mov a,M
        out DAY1_THR_O
        jmp exitok

; I_DAY2_THR_SET VAL=X
dayth2: mov a,M         ; VAL
; must be 2..8F
        cpi 2
        jm badval
        ani 80h
        jz th2ok
        mov a,M
        ani 7Fh
        cpi 10h
        jp badval       ; >8F
th2ok:  mov a,M
        out DAY2_THR_O
        jmp exitok

; I_X1PVCF MM=XXXX
; send 1 PVCF from MM
x1pvcf: 
; HL points to MM addr
; Copy PVCF from MM to RAM, then from RAM
; to SC buffer 1
        xchg            ; DE points to source MM=XXXX
        lxi h,GBL_BPVCF ; temporary RAM
        lxi b,1108/4    ; number of words
        call mm_fetch
        lxi d,GBL_PP_MMSC1 ; destination MM (Spacecraft Buffer 1)
        call mm_store
;
; now set the PVCF counter to 1
; and force a flush
        mvi a,0
        sta GBL_SOH+71    ; N PVCFS in BUF1 (big endian)
        mvi a,1
        sta GBL_SOH+72
        call SC_FLUSH
        jmp exitok


; I_RUN BANK=X
run:    
; select the Memory Bank
        mov a,M         ; BANK
        out BANK_SELECT_O   ; set bank
; Verify checksum
        call CHKB
        cpi 0
        jnz chkbad      ; checksum didn't verify
; jump to code in "DPU.A" which will
; copy the EEPROM to RAM and execute it
        public DPU_RUN
        jmp DPU_RUN

; I_CHK BANK=X REV=X
chk:    mov a,M         ; BANK
        out BANK_SELECT_O
        call CHKB
        cpi 0
        jz chkok
chkbad: mvi a,11 ; ERR_CHKS  ; bad checksum
        jmp exit
chkok:  inx h    
        mov a,M         ; REV
        lxi h,07FFCh
        cmp M           ; right version?
        jz exitok
        mvi a,12 ; ERR_CHKR  ; bad version
        jmp exit

; Verify checksum of currently-selected Bank.
; last 4 bytes of bank are expected to be:
;  Revision Code
;  Byte count (2 bytes, big endian)
;  Checksum
; returns: 0=OK, 1=bad checksum
        public CHKB
chkb:   push h
        push d
        push b
; get number of bytes (big endian) to checksum
        lda 07FFDh
        ani 3Fh         ; force max
        mov b,a
        lda 07FFEh
        mov c,a
        lxi h,4000h     ; start here
        mvi d,0         ; D accumulates the checksum 
        out WATCHDOG_PET_O
chk1:   mov a,d
        xra M           ; XOR byte
        mov d,a
        inx h
        dcx b
        mov a,b
        ora c           ; BC=0?
        jnz chk1
        lxi h,7FFFh
        mov a,M
        cmp d           ; compare checksum
        jnz badchk
        mvi a,0
ckxit:  pop b
        pop d
        pop h
        ret
badchk:
        mvi a,1
        jmp ckxit

; I_TTLIST_DUMP
ttd:
        call cmd_dtt
        jmp exitok

; I_NOP
inop:   
        call debug_asc
        asc "(NOP)$"
        jmp exitok

; I_TRIGGER_DELAY_SET  MSEC=XX
trigger_delay_set:
        mov d,M
        inx h
        mov e,M
        xchg            ; MSEC in HL
; (store little-endian)
        shld GBL_TRIGGER_DELAY
        jmp exitok

; I_TIMED_STIM CHAN_MASK=X MSECS=XX
timed_stim:
        mov a,M         ; CHAN_MASK=X
; turn selected stims on
        out STIM_CTL_O
        inx h
; delay milliseconds
        mov d,M         ; MSECS=XX
        inx h
        mov e,M
dlyms:  call wait_1ms
        dcx d
        mov a,d
        ora e
        jnz dlyms

; now turn stims off
        mvi a,0
        out STIM_CTL_O
        jmp exitok




