view src/divemode.asm @ 20:9b7dd3103545

minor cleanup
author heinrichsweikamp
date Wed, 03 Jul 2013 23:19:57 +0200
parents 11d4fc797f74
children e402813343b6
line wrap: on
line source

;=============================================================================
;
;   File divemode.asm
;
;   Divemode
;
;   Copyright (c) 2011, JD Gascuel, HeinrichsWeikamp, all right reserved.
;=============================================================================
; HISTORY
;  2011-08-15 : [mH] moving from OSTC code

#include    "ostc3.inc"                  ; Mandatory header
#include 	"shared_definitions.h"         ; Mailbox from/to p2_deco.c
#include	"tft_outputs.inc"
#include 	"strings.inc"
#include 	"tft.inc"
#include	"eeprom_rs232.inc"
#include	"isr.inc"
#include	"math.inc"
#include	"wait.inc"
#include	"customview.inc"
#include	"start.inc"
#include	"adc_lightsensor.inc"
#include	"ghostwriter.inc"
#include    "i2c.inc"

gui     CODE

	global	diveloop
diveloop:
    banksel common
	call	speed_normal
	call	diveloop_boot			; Boot tasks for all modes

; Startup Tasks for all modes
	call	TFT_ClearScreen			; clean up TFT
	call	TFT_divemode_mask		; Display mask
	call	TFT_temp_divemode		; Displays temperature

	btfsc	FLAG_apnoe_mode
	bsf		realdive					; Set Realdive flag in Apnoe mode

	btfsc	FLAG_apnoe_mode             ; Done for Apnoe or Gauge mode
    bra     diveloop_loop
	btfsc	FLAG_gauge_mode             ; Done for Apnoe or Gauge mode
	bra     diveloop_loop

	call	TFT_active_gas_divemode     ; Display gas/Setpoint
	call	TFT_display_ndl_mask		; display "NDL"

	; +@5 init
    setf        WREG                    ; WAIT marker: display "---"
    movff       WREG,int_O_extra_ascenttime+0
    movff       WREG,int_O_extra_ascenttime+1
	movlw       1
    movwf       apnoe_mins              ; Start compute after next cycle.

;--------------------------------------------------------------------------------------------------------
diveloop_loop:		; The diveloop starts here
	btfss	onesecupdate					
	bra		diveloop_loop3

; tasks any new second...
	btfsc	FLAG_apnoe_mode					; Only in apnoe mode
	bra		diveloop_loop1b					; One Second Tasks in Apnoe mode

	call	TFT_divemins					; Display (new) divetime!
	call	customview_second				; Do every-second tasks for the custom view area

; Tasks only for deco modes
	call	calc_deko_divemode				; calculate decompression and display result (any two seconds)
	bra		diveloop_loop1x					; Common Tasks

diveloop_loop1b:
; Tasks only for Apnoe mode
	call	divemode_apnoe_tasks			; 1 sec. Apnoe tasks
	bra		diveloop_loop1x					; Common Tasks

diveloop_loop1x:
; Common 1sec. tasks for all modes
	call	timeout_divemode				; dive finished? This routine sets the required flags
	call	set_dive_modes                  ; tests if depth>threshold
	call	set_min_temp                    ; store min. temp if required

	btfsc	store_sample					; store new sample?
	call	store_dive_data					; Store profile data

	btfss	divemode						; Dive finished?
	goto	ghostwriter_end_dive    		; Dive finished!

    btfsc   divemode_gaschange              ; Gas switch flag set?
    rcall   gas_switched_common             ; Yes

    btfsc   toggle_gf                       ; =1: Toggle GF/aGF
    rcall   divemodemode_togglegf           ; Toggle aGF/GF

;    btfsc   FLAG_ccr_mode                   ; In CCR mode
;    call    TFT_active_gas_divemode         ; Update Setpoint every second

	bcf		onesecupdate					; one seconds update done

diveloop_loop3:
	rcall	test_switches_divemode			; Check switches in divemode

    global  diveloop_loop4
diveloop_loop4:                             ; Menu-Exit returns here...
	btfsc	toggle_customview				; Next view?
	call	customview_toggle				; Yes, show next customview (and delete this flag)

	btfsc	pressure_refresh				; new pressure available?
	rcall	update_temp_and_or_depth        ; Yes, display new depth and clear 	"pressure_refresh" flag

	btfsc	oneminupdate					; one minute tasks
	rcall	update_divemode60				; Update clock, etc.

    btfss   quarter_second_update
    bra     diveloop_loop4a
    bcf     quarter_second_update
    movlw   .6
    cpfseq  menupos3                    ; in compass view?
    bra     diveloop_loop4a             ; No
    call    TFT_dive_compass_heading    ; Yes, update compass heading value
diveloop_loop4a:
    btfsc   enable_screen_dumps         ; =1: Ignore vin_usb, wait for "l" command (Screen dump)
    bra     diveloop_loop5
    bra     diveloop_loop6
diveloop_loop5:
    btfss   vusb_in                     ; USB (still) plugged in?
    bcf     enable_screen_dumps         ; No, clear flag
    call    rs232_get_byte
    btfsc   rs232_recieve_overflow
    bra     diveloop_loop6
    movlw   "l"
    cpfseq	RCREG1
    bra     diveloop_loop6
    call    TFT_dump_screen             ; Dump the screen contents
diveloop_loop6:

	bra		diveloop_loop					; Loop the divemode
;--------------------------------------------------------------------------------------------------------






divemode_apnoe_tasks:                       ; 1 sec. Apnoe tasks
	call	TFT_display_apnoe_descent		; Show descent timer
	call	TFT_max_pressure				; use normal max. depth

	btfsc	divemode2						; Time running?
	bra		divemode_apnoe_tasks2			; New descent, reset data if flag is set

	rcall	apnoe_calc_maxdepth
	call	TFT_display_apnoe_surface
	call	TFT_display_apnoe_last_max		; Show last max. depth
	incf	apnoe_surface_secs,F
	movlw	d'60'
	cpfseq	apnoe_surface_secs
	bra		divemode_apnoe_tasks1
	clrf	apnoe_surface_secs
	incf	apnoe_surface_mins,F

divemode_apnoe_tasks1:	
	bcf		FLAG_active_descent				; Clear flag
	btfsc	divemode2						; Time running?
	return									; Yes, return
	bsf		FLAG_active_descent				; Set Flag
	return

divemode_apnoe_tasks2:
	btfss	FLAG_active_descent				; Are we descending?
	return									; No, We are at the surface
	rcall	apnoe_calc_maxdepth				; Yes!
	call	TFT_apnoe_clear_surface			; Clear Surface timer
	clrf	apnoe_timeout_counter			; Delete timeout
	clrf	apnoe_surface_secs
	clrf	apnoe_surface_mins
	clrf	apnoe_secs
	clrf	apnoe_mins						; Reset Descent time
	movlw	.0
	movff	WREG,max_pressure+0
	movff	WREG,max_pressure+1				; Reset Max. Depth
	bcf		FLAG_active_descent				; Clear flag
	return

	global	apnoe_calc_maxdepth
apnoe_calc_maxdepth:
	movff	apnoe_max_pressure+0,sub_a+0
	movff	apnoe_max_pressure+1,sub_a+1
	movff	max_pressure+0,sub_b+0
	movff	max_pressure+1,sub_b+1
	call	subU16				; sub_c = sub_a - sub_b
								; apnoe_max_pressure<max_pressure -> neg_flag=1
								; max_pressure<=apnoe_max_pressure -> neg_flag=0
	btfss	neg_flag	
	return
								;apnoe_max_pressure<max_pressure
	movff	max_pressure+0,apnoe_max_pressure+0
	movff	max_pressure+1,apnoe_max_pressure+1
	return


calc_deko_divemode:
	btfsc	twosecupdate			; two seconds after the last call
	bra		calc_deko_divemode2		; Yes, calculate and display deco data ("first second")

	bsf		twosecupdate			; No, but next second!
	; Routines used in the "other second"
	call	calc_average_depth          ; calculate average depth
	call	calc_velocity               ; calculate vertical velocity and display if > threshold (every two seconds)
	call	divemode_check_for_warnings		; Check for any warnings
	call	TFT_debug_output

	btfsc	FLAG_apnoe_mode             ; Done for Apnoe or Gauge mode
    return
	btfsc	FLAG_gauge_mode             ; Done for Apnoe or Gauge mode
	return

; Calculate CNS
    rcall   set_actual_ppo2             ; Set char_I_actual_ppO2
    clrf    WREG
    movff   WREG,char_I_step_is_1min    ; Make sure to be in 2sec mode.
	call	deco_calc_CNS_fraction		; calculate CNS
	movlb	b'00000001'					; rambank 1 selected

; Check for a gas change
	rcall	check_gas_change			; Checks if a better gas should be selected (by user)

 	return

    global  set_actual_ppo2
set_actual_ppo2:                        ; calculate ppO2 in 0.01bar (e.g. 150 = 1.50 bar ppO2)
    SAFE_2BYTE_COPY amb_pressure, xA    ; P_amb in millibar (1000 = 1.00 bar).
	movlw		d'10'
	movwf		xB+0
	clrf		xB+1
	call		div16x16				; xC=p_amb/10 (100 = 1.00 bar).
	movff		xC+0,xA+0
	movff		xC+1,xA+1
	movff		char_I_O2_ratio,xB+0
	clrf		xB+1
	call		mult16x16				; char_I_O2_ratio * (p_amb/10)
	movff		xC+0,xA+0
	movff		xC+1,xA+1
	movlw		d'100'
	movwf		xB+0
	clrf		xB+1
	call		div16x16				; xC=(char_I_O2_ratio * p_amb/10)/100

; Copy ppO2 for CNS calculation
    tstfsz      xC+1                    ; Is ppO2 > 2.55bar ?
    setf        xC+0                    ; yes: bound to 2.55... better than wrap around.

    movff		xC+0, char_I_actual_ppO2	; copy last ppO2 to buffer register
    btfsc       is_bailout                  ; In Bailout?
    return                                  ; Yes, done.
    ; No Bailout, check for ccr mode
    btfsc		FLAG_ccr_mode               ; If FLAG_ccr_mode=1...
    movff		char_I_const_ppO2, char_I_actual_ppO2	; ...copy last ppO2 to buffer register
    return


calc_deko_divemode2:
	bcf		twosecupdate		

	btfsc	FLAG_apnoe_mode             ; Done for Apnoe or Gauge mode
    return
	btfsc	FLAG_gauge_mode             ; Done for Apnoe or Gauge mode
	return

	extern	deco_setup_dive
	call	deco_setup_dive				;  Pass all parameters to the C code

    TSTOSS  opt_ccr_mode                    ; =0: Fixed SP, =1: Sensor
    bra     calc_deko_divemode2a
    rcall   divemode_setup_sensor_values    ; Setup sensor values

calc_deko_divemode2a:
	SAFE_2BYTE_COPY amb_pressure,int_I_pres_respiration ; C-code needs the ambient pressure
	clrf	WREG
	movff	WREG,char_I_step_is_1min    ; Force 2 second deco mode

    clrf    TMR5L
    clrf    TMR5H                       ; 30,51757813µs/bit in TMR5L:TMR5H
	call	deco_calc_hauptroutine		; calc_tissue
    movlb   .1

    movff   char_O_deco_status,WREG     ; Is a compute cycle finished ?
    iorwf   WREG,F
    btfss   STATUS,Z
    return                              ; Return is status <> 0

    ; Check if deco stops are necessary ?
	movff	char_O_first_deco_depth,wait_temp	; copy ceiling to temp register
	tstfsz	wait_temp							; Ceiling<0m?
	bra		calc_deko_divemode3					; Yes!

	btfsc	decostop_active             ; Already in nodeco mode ?
	call	TFT_display_ndl_mask       	; No, Clear deco data, display nostop time
	bcf		decostop_active             ; clear flag (again)

	; Copy for profile recording
	clrf	decodata+0
	movff	char_O_nullzeit,decodata+1  ; NDL
	
	call	TFT_display_ndl            ; display no deco limit
	return

calc_deko_divemode3:
	btfss	decostop_active            ; Already in deco mode ?
	call	TFT_display_deko_mask      ; No, clear nostop time, display decodata
	bsf		decostop_active            ; Set flag (again)

	; Copy for profile recording
	movff	char_O_first_deco_depth,decodata+0	; ceiling
	movff	char_O_first_deco_time,decodata+1	; length of first stop in minues
	call	TFT_display_deko            ; display decodata
	call	TFT_show_TTS_divemode       ; display TTS

    movff   char_I_extra_time,WREG
    tstfsz  WREG                    ; extra time = 0?
    bra     calc_deko_divemode4     ; No, compute it
    return

calc_deko_divemode4:
    ; Check if extra cycles are needed to compute @5 variant:
	decfsz  apnoe_mins,F                ; Reached count-down ?
	return                              ; No: don't compute yet.
	
	movlw   .6
	movff   WREG,char_O_deco_status     ; Stole next cycles for @5 variant.
    
    movlw   .2                          ; Restart countdown.
    movwf   apnoe_mins
 	return                              ; done.
   
;-----------------------------------------------------------------------------

divemodemode_togglegf:                  ; Toggle aGF/GF
    bcf     toggle_gf                   ; clear flag    
    btg     use_agf                     ; Toggle GF
    call    TFT_gf_mask                 ; Setup Mask
    clrf    WREG
    movff   WREG,char_O_deco_status     ; Restart decoplan computation
    return

divemode_setup_sensor_values:
    ; sum up sensor values (in xA:2) and active sensors in (xB:2)
    clrf    xB+0
    clrf    xB+1
    clrf    xA+0
    clrf    xA+1
    btfss   hud_status_byte,3               ; Sensor1 active?
    bra     divemode_setup_sensor_values2   ; No
    movf    o2_ppo2_sensor1,W
    addwf   xA+0
    movlw   .0
    addwfc  xA+1                            ; Add into xA:2
    incf    xB+0,F                          ; Add a sensor
divemode_setup_sensor_values2:
    btfss   hud_status_byte,4               ; Sensor2 active?
    bra     divemode_setup_sensor_values3   ; No
    movf    o2_ppo2_sensor2,W
    addwf   xA+0
    movlw   .0
    addwfc  xA+1                            ; Add into xA:2
    incf    xB+0,F                          ; Add a sensor
divemode_setup_sensor_values3:
    btfss   hud_status_byte,5               ; Sensor3 active?
    bra     divemode_setup_sensor_values4   ; No
    movf    o2_ppo2_sensor3,W
    addwf   xA+0
    movlw   .0
    addwfc  xA+1                            ; Add into xA:2
    incf    xB+0,F                          ; Add a sensor
divemode_setup_sensor_values4:
    call    div16x16						; xA/xB=xC with xA+0 as remainder
    movff   xC+0,sensor_setpoint            ; Copy result
    movff   sensor_setpoint,char_I_const_ppO2 ; use sensor ppO2
    return

calc_velocity:								; called every two seconds
	btfss	divemode						
	bra		do_not_display_velocity			; display velocity only in divemode (Not at the surface after dive)

calc_velocity2:
    SAFE_2BYTE_COPY amb_pressure, sub_a
	movff	last_pressure_velocity+0,sub_b+0
	movff	last_pressure_velocity+1,sub_b+1
	movff	sub_a+0,last_pressure_velocity+0	; store old value for velocity
	movff	sub_a+1,last_pressure_velocity+1

	call	subU16						; sub_c = amb_pressure - last_pressure

	movff	sub_c+0,xA+0
	movff	sub_c+1,xA+1
	movlw	d'39'						; 77 when called every second....
	movwf	xB+0
	clrf	xB+1
	call	mult16x16					; differential pressure in mbar*77...
	movff	xC+0,divA+0
	movff	xC+1,divA+1
	movlw	d'7'
	movwf	divB+0
	call	div16						; devided by 2^7 equals velocity in m/min

	movlw	d'99'
	cpfsgt	divA+0                      ; limit to 99m/min
	bra		calc_velocity3
	movwf	divA+0						; divA=99

calc_velocity3:
	movlw	velocity_warning_level_1	; lowest threshold for display vertical velocity
	subwf	divA+0,W					; 
	btfss	STATUS,C
	bra		do_not_display_velocity

	bsf		display_velocity
	call	TFT_display_velocity		; With divA+0 = m/min...
	return

do_not_display_velocity:
	btfss	display_velocity			; Velocity was not displayed, do not delete
	return
	bcf		display_velocity			; Velocity was displayed, delete velocity now
	call	TFT_display_velocity_clear
	return

;=============================================================================

timeout_menuview:
    decfsz  timeout_counter3,F          ; timeout for menuview
    return                              ; No timeout, return
    ; Timeout, clear e.g. "Menu?"
    goto    menuview_toggle_reset       ; "returns"

timeout_divemode_menu:
    decfsz  timeout_counter3,F          ; timeout for divemode menu
    return

    global  timeout_divemode_menu2
timeout_divemode_menu2:                 ; Called from divemenu_tree.asm
    bcf     divemode_menu               ; Timeout! Clear flag
    call    TFT_clear_divemode_menu     ; Clear menu
    call    TFT_active_gas_divemode     ; Redraw gas/setpoint/diluent
    bcf     blinking_better_gas         ; Clear flag to have temperature updated once
    call	TFT_temp_divemode           ; Displays temperature

    btfss   decostop_active             ; In deco mode ?
    bra     timeout_divemode_menu_ndl   ; No, show NDL again
    ; Show deco
	call	TFT_display_deko_mask      ; clear nostop time, display decodata
    call    TFT_display_deko
    call    TFT_show_TTS_divemode
    return
timeout_divemode_menu_ndl:              ; Show NDL
	call	TFT_display_ndl_mask       	; Clear deco data, display nostop time
    call    TFT_display_ndl
    return

timeout_divemode:
    btfsc   divemode_menu               ; Divemode menu active?
    rcall   timeout_divemode_menu       ; Yes, check the timeout for it...

    btfsc   menuview                    ; is a menuview shown?
    rcall   timeout_menuview            ; Yes, check the timeout for it...

	btfss	realdive					; Dive longer then one minute
	return
	
	btfsc	FLAG_apnoe_mode				; In Apnoe mode?
	bra		timeout_divemode2			; Yes, use CF30 [min] for timeout

    ifndef __DEBUG
    	btfsc	simulatormode_active    ; In Simulator mode?
    	bra		timeout_divemode3       ; Yes, use simulator timeout
    endif
	
	bcf		divemode
	incf	timeout_counter,F
	movlw	d'0'
	addwfc	timeout_counter2,F			; timeout is 15bits

	movlw	LOW		divemode_timeout
	movwf	sub_a+0
	movlw	HIGH	divemode_timeout
	movwf	sub_a+1

	movff	timeout_counter, sub_b+0
	movff	timeout_counter2, sub_b+1
	call	subU16						;  sub_c = sub_a - sub_b
	btfss	neg_flag					; Result negative?
	bsf		divemode					; No, set flag
	return

timeout_divemode2:
	incf	timeout_counter,F			; seconds...
	movlw	d'60'
	cpfseq	timeout_counter				; timeout_counter=60?
	return								; No.
; One minute timeout done.
	clrf	timeout_counter
	bcf		divemode
	incf	apnoe_timeout_counter,F
	movlw	apnoe_timeout				; apnoe timeout [min]
	cpfseq	apnoe_timeout_counter
	bsf		divemode
	return

timeout_divemode3:
	bcf		divemode
	incf	timeout_counter,F
	movlw	simulator_timeout   		; simulator timeout
	cpfsgt	timeout_counter
	bsf		divemode
	return

update_temp_and_or_depth:			    ; New sensor data arrived...
	btfsc	temp_changed	
	call	TFT_temp_divemode		    ; Displays temperature

	btfsc	pressure_refresh
	call	TFT_depth					; Displays new depth

	rcall	set_max_depth               ; update max. depth if required
	bcf		pressure_refresh			; until new pressure is available
	return

update_divemode60:                      ; update any minute
	call	get_battery_voltage			; gets battery voltage
	call	set_powersafe				; Battery low?
	call	TFT_max_pressure			; Update max. depth
	call	customview_minute			; Do every-minute tasks for the custom view area
	bcf		oneminupdate

    btfss   simulatormode_active        ; in simulator mode?
	return                              ; No
	; Yes, quite dive mode simulation after 21*256s=89min:36s
	movlw	.20
	cpfsgt	total_divetime_seconds+1	; Timeout?
	return                              ; No
    ifdef __DEBUG
    return                              ; No simulator timeout in debug mode
    endif
	bra		divemode_option1            ; Yes, set to 0m and "return"

set_max_depth:
	movff	max_pressure+0,sub_a+0
	movff	max_pressure+1,sub_a+1
    SAFE_2BYTE_COPY rel_pressure, sub_b
	call	subU16                      ; sub_c = sub_a - sub_b
                                        ; max_pressure<rel_pressure -> neg_flag=1
                                        ; rel_pressure<=max_pressure -> neg_flag=0
	btfss	neg_flag	
	return
                                        ; max_pressure<rel_pressure
	movff	sub_b+0,max_pressure+0
	movff	sub_b+1,max_pressure+1
	call	TFT_max_pressure			; No, use normal max. depth
	return

set_min_temp:
	movff	minimum_temperature+0,sub_a+0
	movff	minimum_temperature+1,sub_a+1
    SAFE_2BYTE_COPY temperature,sub_b
	call	sub16                       ; sub_c = sub_a - sub_b
                                        ; minimum_temperature<T -> neg_flag=1
                                        ; T<=minimum_temperature -> neg_flag=0
	btfsc	neg_flag	
	return
                                        ; minimum_temperature>=T
	movff	sub_b+0,minimum_temperature+0
	movff	sub_b+1,minimum_temperature+1
	return

	global	set_dive_modes
set_dive_modes:
	btfsc	high_altitude_mode		; In high altitude (Fly) mode?
	bra		set_dive_modes3			; Yes!

set_dive_modes0:
	movlw	LOW		start_dive_threshold
	movwf	sub_a+0					; dive_treshold is in cm
	movlw	HIGH	start_dive_threshold
	movwf	sub_a+1					; dive_treshold is in cm

set_dive_modes1:
    SAFE_2BYTE_COPY rel_pressure, sub_b
	call	subU16					; sub_c = sub_a - sub_b

	btfss	neg_flag	
	bra		set_dive_modes2			; too shallow (rel_pressure<dive_threshold)

	btfsc	realdive				; Dive longer than one minute?
	clrf 	timeout_counter			; Yes, reset timout counter

set_dive_modes_common:
	bsf		divemode				; (Re-)Set divemode flag
	bsf		divemode2				; displayed divetime is running
	return

set_dive_modes2:
	bcf		divemode2				; Stop time
	btfss	realdive				; dive longer then one minute?
	bcf		divemode				; no -> this was no real dive
	return							; No, return


set_dive_modes3:					; High-altitude mode
	btfsc	realdive				; dive longer then one minute?
	bra		set_dive_modes0			; Yes -> this is a real dive -> Use start_dive_threshold or ascend

	movlw	HIGH	high_altitude_dive_threshold
	movwf	sub_a+1
	movlw	LOW		high_altitude_dive_threshold
	movwf	sub_a+0
	bra		set_dive_modes1

set_powersafe:
    movlw   color_code_battery_low+1; [%]
    cpfslt  batt_percent
	return

	movlw	d'7'					; Type of Alarm (Battery Low)
	movwf	AlarmType				; Copy to Alarm Register
	bsf		event_occured			; Set Event Flag
    movlw   .0
    movff   WREG,opt_brightness     ; Set Brightness to ECO
	return							; return

calc_average_depth:
	btfsc	reset_average_depth		; Reset the Avewrage depth?
	rcall	reset_average1			; Reset the resettable average depth

	; 1. Add new 2xdepth to the Sum of depths registers
    SAFE_2BYTE_COPY rel_pressure, xB	; Buffer...
    bcf     STATUS,C
    rlcf    xB+0,F
    rlcf    xB+1,F                  ; x2

	movf	xB+0,w
	addwf	average_depth_hold+0,F
	movf	xB+1,w
	addwfc	average_depth_hold+1,F
	movlw	d'0'
	addwfc	average_depth_hold+2,F
	addwfc	average_depth_hold+3,F ; Will work up to 9999mbar*60*60*24=863913600mbar

; Do the same for the _total registers (Non-Resettable)
	movf	xB+0,w
	addwf	average_depth_hold_total+0,F
	movf	xB+1,w
	addwfc	average_depth_hold_total+1,F
	movlw	d'0'
	addwfc	average_depth_hold_total+2,F
	addwfc	average_depth_hold_total+3,F ; Will work up to 9999mbar*60*60*24=863913600mbar

	; 2. Compute Average Depth on base of average_divesecs:2
	movff	average_divesecs+0,xB+0
	movff	average_divesecs+1,xB+1		; Copy
	movff	average_depth_hold+0,xC+0
	movff	average_depth_hold+1,xC+1
	movff	average_depth_hold+2,xC+2
	movff	average_depth_hold+3,xC+3

	call	div32x16 	; xC:4 / xB:2 = xC+3:xC+2 with xC+1:xC+0 as remainder
	movff	xC+0,avr_rel_pressure+0
	movff	xC+1,avr_rel_pressure+1

	; 3. Compute Total Average Depth on base of total_divetime_seconds:2
	movff	total_divetime_seconds+0,xB+0
	movff	total_divetime_seconds+1,xB+1		; Copy
	movff	average_depth_hold_total+0,xC+0
	movff	average_depth_hold_total+1,xC+1
	movff	average_depth_hold_total+2,xC+2
	movff	average_depth_hold_total+3,xC+3
	call	div32x16 	; xC:4 / xB:2 = xC+3:xC+2 with xC+1:xC+0 as remainder
	movff	xC+0,avr_rel_pressure_total+0
	movff	xC+1,avr_rel_pressure_total+1

;	; Compute Total Average Depth on base of divemins:2 and divesecs
;	movff	divemins+0,xA+0
;	movff	divemins+1,xA+1
;	movlw	d'60'
;	movwf	xB+0
;	clrf	xB+1
;	call	mult16x16				; xC:4=xA:2*xB:2
;	movf	divesecs,W
;	addwf	xC+0,F
;	movlw	d'0'
;	addwfc	xC+1,F					; xC:2 holds total dive seconds
;	movlw	d'3'					; 2+1
;	btfss	divesecs,0				; divesecs even?
;	movlw	d'2'					; Yes, do not add +1
;	addwf	xC+0,F
;	movlw	d'0'
;	addwfc	xC+1,F
;	; Ignore xC+2 and xC+3. Total Average will only work up to divetime=1092:16
;	movff	xC+0,xB+0
;	movff	xC+1,xB+1		; Copy
;	movff	average_depth_hold_total+0,xC+0
;	movff	average_depth_hold_total+1,xC+1
;	movff	average_depth_hold_total+2,xC+2
;	movff	average_depth_hold_total+3,xC+3
;
;	call	div32x16 	; xC:4 / xB:2 = xC+3:xC+2 with xC+1:xC+0 as remainder
;	movff	xC+0,avr_rel_pressure_total+0
;	movff	xC+1,avr_rel_pressure_total+1

	return

reset_average1:
	clrf	average_depth_hold+0
	clrf	average_depth_hold+1
	clrf	average_depth_hold+2
	clrf	average_depth_hold+3		; Clear average depth register
	movlw	d'2'
	movwf	average_divesecs+0
	clrf	average_divesecs+1
	bcf		reset_average_depth			; Clear flag
	return

test_switches_divemode:		; checks switches in divemode
    btfsc   divemode_menu               ; Divemode menu shown?
    bra     test_switches_divemode_menu ; Yes, use menu processor
	btfsc	switch_left
	bra		test_switches_divemode2		; Enter button pressed, check if we need to do something
	btfss	switch_right
	return                              ; No button press
    tstfsz  menupos2                    ; any option shown?
    bra     test_switches_divemode1     ; Yes, do option tasks
	bsf		toggle_customview           ; No, toggle custom view
    return

test_switches_divemode_menu:
	btfsc	switch_left
	bra		test_switches_divemode_menu2    ; Move cursor
	btfsc	switch_right
    bra		test_switches_divemode_menu3    ; Enter submenu or do something
    return                                  ; No button press

test_switches_divemode_menu1:
    clrf    menupos
test_switches_divemode_menu2:
    incf    menupos,F
    incf    menupos4,W                  ; menupos4+1 -> WREG
    cpfslt  menupos                     ; >menupos4 (Set in menu_processor.asm)?
    bra     test_switches_divemode_menu1; > Yes, set to 1
    call    TFT_divemode_menu_cursor    ; Update the cursor
    bcf     switch_left
	movlw	divemode_menu_timeout       ; Reload timeout
	movwf	timeout_counter3            ; timeout for divemode menu
    return

test_switches_divemode_menu3:           ; Enter submenu or do something
    bcf     switch_right
;    decf    menupos,F                   ; menu_processor needs 0-5...
    extern  do_line_menu
    goto    do_line_menu                ; Warning! Trashes STKPTR and returns to diveloop_loop4:

test_switches_divemode1:
	bcf		switch_right
    movlw   divemode_menuview_timeout
    movwf   timeout_counter3            ; Reload timeout
	movff	menupos2,WREG               ; Menupos3 holds number of customview/divemode menu function
	dcfsnz	WREG,F
    bra		divemode_option0			; Start/Setup Divemode menu
	dcfsnz	WREG,F
	bra		divemode_option1			; Quit Simulation?
	dcfsnz	WREG,F
	bra		divemode_option2			; Descent 1m
	dcfsnz	WREG,F
	bra		divemode_option3			; Ascend 1m
	dcfsnz	WREG,F
	bra		divemode_option4			; Quit Apnoe mode
	dcfsnz	WREG,F
	bra		divemode_option5			; Reset Stopwatch (In Gauge mode)
    return

test_switches_divemode2:
	bcf		switch_left
    call    menuview_toggle         ; Menu or Simulator tasks
    return

gas_switched_common:
    decf    menupos,W               ; 1-5 -> 0-4
    btfss   FLAG_ccr_mode           ; Choose OC Gases
    rcall   setup_gas_registers     ; With WREG=Gas 0-4
    btfsc   FLAG_ccr_mode           ; Choose CC Diluents
    rcall   setup_dil_registers     ; With WREG=Gas 0-4

    decf    menupos,W               ; 1-5 -> 0-4
    btfsc   is_bailout              ; Choose OC Bailouts (OC Gases)
    rcall   setup_gas_registers     ; With WREG=Gas 0-4

    call	TFT_active_gas_divemode	; Display gas/Setpoint
	bsf		event_occured			; Set global event byte
	bsf		stored_gas_changed		; Set Flag for profile
    bcf     divemode_gaschange      ; Clear flag
    clrf    WREG
    movff   WREG,char_O_deco_status ; Restart decoplan computation
	return

    global  setup_gas_registers
setup_gas_registers:                ; With WREG=Gas 0-4
    lfsr    FSR1,opt_gas_O2_ratio+0
    movff   PLUSW1,char_I_O2_ratio  ; O2 (For ppO2 calculations)
    lfsr    FSR1,opt_gas_He_ratio+0
    movff   PLUSW1,char_I_He_ratio  ; He
    incf    WREG,W                  ; Gas# 1-5
	movff	WREG,char_I_current_gas	; Set gas
	movff	WREG,active_gas			; Set for logbook and display
    banksel char_I_O2_ratio
	movf    char_I_O2_ratio,W       ; Add O2...
    addwf   char_I_He_ratio,W       ; ...and He...
	sublw   .100                    ; ...subtract both from 100
	movwf   char_I_N2_ratio         ; -> N2!
    banksel common
    return

    global  setup_dil_registers
setup_dil_registers:                ; With WREG=dil 0-4
    lfsr    FSR1,opt_dil_O2_ratio+0
    movff   PLUSW1,char_I_O2_ratio  ; O2 (For ppO2 calculations)
    lfsr    FSR1,opt_dil_He_ratio+0
    movff   PLUSW1,char_I_He_ratio  ; He
    incf    WREG,W                  ; Gas# 1-5
	movff	WREG,char_I_current_gas	; Set gas
	movff	WREG,active_gas			; Set for logbook and display
    banksel char_I_O2_ratio
	movf    char_I_O2_ratio,W       ; Add O2...
    addwf   char_I_He_ratio,W       ; ...and He...
	sublw   .100                    ; ...subtract both from 100
	movwf   char_I_N2_ratio         ; -> N2!
    banksel common
    return

divemode_option0:                   ; Start/Setup Divemode menu
    call    TFT_clear_divemode_menu ; Clear menu area
    bcf     menuview
    extern  do_main_divemenu
    call    do_main_divemenu
    global  divemode_option0_return
divemode_option0_return:
;    movlw   .1
;    movwf   menupos                 ; Set to first option in divemode menu
    call    TFT_divemode_menu_cursor; Show the cursor
	movlw	divemode_menu_timeout
	movwf	timeout_counter3        ; timeout for divemode menu
    bsf     divemode_menu           ; Set flag
    clrf    menupos2                ; Clear option counter
    bra     diveloop_loop4          ; Goto back to diveloop (Menuprocessor trashes STKPTR!)

divemode_option4:
	movlw	d'58'					; two seconds left
	movwf	timeout_counter
	movlw	apnoe_timeout-1			; apnoe timeout [min]
	movwf	apnoe_timeout_counter
    btfss   simulatormode_active	; in simulator mode?
	return							; No
divemode_option1:						; Quit simulation mode
	banksel	isr_backup
    movlw   low     .1000
    movwf	sim_pressure+0
    movlw   high    .1000
	movwf   sim_pressure+1			; Set to 0m -> End of Dive
	banksel common
    call    menuview_toggle_reset   ; Reset to zero (Zero=no menuview)
	
	btfss	FLAG_apnoe_mode			; In Apnoe mode?
	return							; No
	movlw	d'58'					; two seconds left
	movwf	timeout_counter
	movlw	apnoe_timeout-1			; apnoe timeout [min]
	movwf	apnoe_timeout_counter
	return

divemode_option3:			; minus 1m
	banksel	isr_backup
	movlw	d'100'
	subwf	sim_pressure+0
	movlw	.0
	subwfb	sim_pressure+1
	rcall	divemode_simulator_check_limits
	banksel common
	return

divemode_option2:			; plus 1m
	banksel	isr_backup
	movlw	d'100'
	addwf	sim_pressure+0
	movlw	.0
	addwfc	sim_pressure+1
	rcall	divemode_simulator_check_limits
	banksel common
	return

divemode_option5:
    call    menuview_toggle_reset   ; Reset to zero (Zero=no menuview)
    bsf     reset_average_depth     ; Set Flag
    return

divemode_simulator_check_limits:
	; Check limits (150m and 0m)
	movlw	LOW		d'16000'            ; Compare to 16bar=16000mbar (150m).
	subwf   sim_pressure+0,W
	movlw	HIGH	d'16000'
	subwfb  sim_pressure+1,W
	bnc     divemode_simulator_check_limits2 ; No-carry = borrow = not deeper

	; Too deep, limit to 150m
	movlw	LOW		d'16000'
	movwf	sim_pressure+0
	movlw	HIGH	d'16000'
	movwf	sim_pressure+1
	return
divemode_simulator_check_limits2:
	movlw	LOW		d'1000'             ; Compare to 1bar == 0m == 1000 mbar.
	subwf   sim_pressure+0,W
	movlw	HIGH	d'1000'
	subwfb  sim_pressure+1,W
	btfsc   STATUS,C                    ; No-carry = borrow = not deeper.
	return                              ; Deeper than 0m == Ok.
	; Too shallow, limit to 0m
	movlw	LOW		d'1000'
	movwf	sim_pressure+0
	movlw	HIGH	d'1000'
	movwf	sim_pressure+1
	return

;=============================================================================
; Compare all enabled gas in list, to see if a better one is available.
;
; Output: better_gas_available, better_gas_number
;
check_gas_change:					; Checks if a better gas should be selected (by user)
	bcf		better_gas_available    ;=1: A better gas is available and a gas change is advised in divemode
	clrf	better_gas_number       ; Clear better gas register

    SAFE_2BYTE_COPY rel_pressure,xA
	movlw	d'100'
	movwf	xB+0
	clrf	xB+1
	call	div16x16				; compute depth in full m -> result in xC+0

    btfss   FLAG_ccr_mode           ; In CCR mode...
    bra     check_gas_change_OC_bail; No, check for OC or bailout
    btfsc   is_bailout              ; Bailout?
    bra     check_gas_change_OC_bail; Yes, check for OC or bailout

    ; Check Diluents
    movlw   .0
    rcall   check_dil_common        ; With Gas 0-4 in WREG
    movlw   .1
    rcall   check_dil_common        ; With Gas 0-4 in WREG
    movlw   .2
    rcall   check_dil_common        ; With Gas 0-4 in WREG
    movlw   .3
    rcall   check_dil_common        ; With Gas 0-4 in WREG
    movlw   .4
    rcall   check_dil_common        ; With Gas 0-4 in WREG
    bra     check_gas_change_exit

check_gas_change_OC_bail:
    movlw   .0
    rcall   check_gas_common        ; With Gas 0-4 in WREG
    movlw   .1
    rcall   check_gas_common        ; With Gas 0-4 in WREG
    movlw   .2
    rcall   check_gas_common        ; With Gas 0-4 in WREG
    movlw   .3
    rcall   check_gas_common        ; With Gas 0-4 in WREG
    movlw   .4
    rcall   check_gas_common        ; With Gas 0-4 in WREG
;    bra     check_gas_change_exit
check_gas_change_exit:
    btfss	better_gas_available	; Is a better gas available
    bcf     blinking_better_gas     ; No, Clear blinking flag
    btfss	better_gas_available	; Is a better gas available
    clrf    better_gas_number		; No, Clear better_gas_number (For gaslist display)
    call    TFT_active_gas_divemode ; Display gas/Setpoint
	return

check_gas_common:                   ; With Gas 0-4 in WREG
    btfsc   better_gas_available	; Better Gas already found?
    return                          ; Yes, return
    lfsr    FSR1,opt_gas_type       ; 0=Disabled, 1=First, 2=Travel, 3=Deco
    btfss   PLUSW1,0                ; Test for Bit0 and 1 -> type=3 -> Deco
    return                          ; No
    btfss   PLUSW1,1                ; Test for Bit0 and 1 -> type=3 -> Deco
    return                          ; No
    incf    WREG,W                  ; 1-5
    cpfseq  active_gas				; is this gas currently selected?
    bra     check_gas_common2       ; No
    return                          ; Yes, skip test for active gas
check_gas_common2:
    decf    WREG,W                  ; 0-4
    movwf   hi                      ; Save tested gas 0-4
    lfsr    FSR1,char_I_deco_gas_change
    movff   PLUSW1,lo               ; Change depth into lo
	movlw	minimum_change_depth
	cpfsgt	lo  					; Change depth>minimum_change_depth?
	return                          ; No, Change depth not deep enough, skip!
	movf	xC+0,W					; load depth in m into WREG
	cpfsgt	lo  					; gas_change_depth < current depth?
    return                          ; No, check next gas
	incf    hi,W                    ; 1-5
	movwf	better_gas_number		; number (1-5) of the "better gas" in divemode, =0: no better gas available
	movlw	better_gas_window
	subwf	lo,W                    ; Change depth-better_gas_window
	cpfslt	xC+0					; current depth<Change depth-better_gas_window?
	bsf		better_gas_available	;=1: A better gas is available and a gas change is advised in divemode
    return

check_dil_common:                   ; With Dil 0-4 in WREG
    btfsc   better_gas_available	; Better Diluent already found?
    return                          ; Yes, return
    lfsr    FSR1,opt_dil_type       ; 0=Disabled, 1=First, 2=Normal
    tstfsz  PLUSW1                  ; =0?
    bra     check_dil_common1       ; No
    return                          ; Yes, skip inactive diluents for test
check_dil_common1:
    incf    WREG,W                  ; 1-5
    cpfseq  active_gas				; is this diluent currently selected?
    bra     check_dil_common2       ; No
    return                          ; Yes, skip test for active diluent
check_dil_common2:
    decf    WREG,W                  ; 0-4
    movwf   hi                      ; Save tested diluent 0-4
    lfsr    FSR1,char_I_dil_change
    movff   PLUSW1,lo               ; Change depth into lo
	movlw	minimum_change_depth
	cpfsgt	lo  					; Change depth>minimum_change_depth?
	return                          ; No, Change depth not deep enough, skip!
	movf	xC+0,W					; load depth in m into WREG
	cpfsgt	lo  					; gas_change_depth < current depth?
    return                          ; No, check next gas
	incf    hi,W                    ; 1-5
    addlw   .5                      ; 6-10
	movwf	better_gas_number		; number (1-5) of the "better gas" in divemode, =0: no better gas available
	movlw	better_gas_window
	subwf	lo,W                    ; Change depth-better_gas_window
	cpfslt	xC+0					; current depth<Change depth-better_gas_window?
	bsf		better_gas_available	;=1: A better gas is available and a gas change is advised in divemode
    return

;=============================================================================
; Setup everything to enter divemode.
;

dive_boot_oc:
    extern  get_first_gas_to_WREG
    call    get_first_gas_to_WREG           ; Gets first gas (0-4) into WREG
    movff   WREG,char_I_first_gas           ; Copy for compatibility
	movff	WREG,active_gas                 ; Set for logbook and display
    rcall   setup_gas_registers             ; With WREG=Gas 0-4
    return

dive_boot_cc:
    rcall   divemode_setup_sensor_values    ; setup sensor values
    TSTOSS  opt_ccr_mode                    ; =0: Fixed SP, =1: Sensor
    movff   char_I_setpoint_cbar+0,char_I_const_ppO2    ; Setup fixed Setpoint (Always start with SP1)
    extern  get_first_dil_to_WREG
    call    get_first_dil_to_WREG           ; Gets first gas (0-4) into WREG
    movff   WREG,char_I_first_gas           ; Copy for compatibility
	movff	WREG,active_gas                 ; Set for logbook and display
    rcall   setup_dil_registers             ; With WREG=Gas 0-4
    return

diveloop_boot:
	call	restart_set_modes_and_flags

    call    I2C_sleep_accelerometer          ; Stop accelerometer
    call    I2C_sleep_compass                ; Stop compass

	clrf	WREG
	movff	WREG,max_pressure+0				; clear some variables
	movff	WREG,max_pressure+1

    bcf     use_agf                         ; Start with normal GF set
    bcf     divemode_menu                   ; clear divemode menu flag
	movlw	d'1'
	movwf	apnoe_max_pressure+0
	clrf	apnoe_max_pressure+1
	clrf	apnoe_surface_mins			
	clrf	apnoe_surface_secs		
	clrf	apnoe_mins
	clrf	apnoe_secs
	clrf	divemins+0
	clrf	divemins+1
    bcf     no_more_divesecs                ; =1: Do no longer show seconds in divemode
	bcf		divemode_menu_active
    clrf    menupos
    clrf	menupos3                        ; Reset to zero (Zero=no custom view)
    clrf    menupos2                        ; Reset to zero (Zero=no premenu or simulator task)

    bcf     is_bailout                      ; =1: Bailout
    btfss   FLAG_ccr_mode
    rcall   dive_boot_oc
    btfsc   FLAG_ccr_mode
    rcall   dive_boot_cc

	bcf		better_gas_available        ;=1: A better gas is available and a gas change is advised in divemode
	clrf	better_gas_number           ; Clear better gas register

 	clrf	samplesecs
	clrf	apnoe_timeout_counter		; timeout in minutes
	clrf 	timeout_counter				; takes care of the timeout (Low byte)
	clrf 	timeout_counter2			; takes care of the timeout (High byte)
	clrf	AlarmType					; Clear all alarms
	bcf		event_occured				; clear flag
	clrf 	total_divetime_seconds+1
	clrf	average_depth_hold_total+0
	clrf	average_depth_hold_total+1
	clrf	average_depth_hold_total+2
	clrf	average_depth_hold_total+3	; Clear Non-Resettable Average
    rcall	reset_average1				; Reset the resettable average depth
    bcf		decostop_active
	bcf		better_gas_available        ;=1: A better gas is available and a gas change is advised in divemode
	call	ghostwriter_short_header		; Write short header with divenumber into profile memory

    btfsc   simulatormode_active
    bra     diveloop_boot_1
    ; Normal mode = Surface pressure is the pressure 30mn before dive.
	SAFE_2BYTE_COPY last_surfpressure_30min, int_I_pres_surface	;copy surfacepressure to deco routine
	SAFE_2BYTE_COPY last_surfpressure_30min, last_surfpressure	;copy surfacepressure to last_surfpressure for correct depth
    bra     diveloop_boot_2

diveloop_boot_1:
    ; Simulator mode: Surface pressure is 1bar.
    movlw   LOW .1000
	movff	WREG,int_I_pres_surface+0   ; LOW copy surfacepressure to deco routine
    movlw   HIGH .1000
	movff	WREG,int_I_pres_surface+1   ; HIGH copy surfacepressure to deco routine

diveloop_boot_2:
	SAFE_2BYTE_COPY	temperature,minimum_temperature ; Reset Min-Temp registers

; Init profile recording parameters	
	movlw	samplingrate
	movwf	samplesecs_value            ; to avoid EEPROM access in the ISR
	movlw	div_temperature
	movwf	divisor_temperature         ; load divisors for profile storage
	movlw	div_deco
	movwf	divisor_deco				
	movlw	div_gf
	movwf	divisor_gf
	movlw	div_ppo2_sensors
	movwf	divisor_ppo2_sensors
	movlw	div_decoplan
	movwf	divisor_decoplan
	movlw	div_cns
	movwf	divisor_cns
	movlw	div_tank
	movwf	divisor_tank

	btfss	FLAG_apnoe_mode				; In Apnoe mode?
	bra		divemode1
; Overwrite some parameters in Apnoe mode....
	movlw	samplingrate_apnoe
	movwf	samplesecs_value			; to avoid EEPROM access in the ISR

divemode1:
	bcf		LEDg
	bcf		LEDr
	bcf		realdive
	btfss	simulatormode_active		; do not disable in simulator mode!					
	call	disable_rs232				; Disable RS232
    btfsc   enable_screen_dumps         ; =1: Ignore vin_usb, wait for "l" command (Screen dump)
    call	enable_rs232				; Also sets to speed_normal ...
    movlw   .2
	movwf   total_divetime_seconds+0
	movwf   divesecs                    ; Start at 2seconds
	bsf		divemode2                   ; displayed divetime is running (Divetime starts HERE)

	movff	int_O_CNS_fraction+0,CNS_start+0
    movff	int_O_CNS_fraction+1,CNS_start+1        ; Save CNS value at beginning of dive
    movff   char_O_relative_gradient_GF,GF_start    ; Save GF value at  beginning of dive
	return								; Done with divemode boot

divemode_check_for_warnings:
    btfss   secs,1                      ; Every four seconds
    return

	movf	warning_counter_backup,W
	cpfseq	warning_counter						; warning_counter_backup = warning_counter?
	call	TFT_clear_warning_text              ; No, clear all warnings
	movff	warning_counter,warning_counter_backup	; copy warning_counter

	bcf		warning_active				; Clear flag
	clrf	warning_counter						; Clear counter

    ; Warnings for all modes
    call	check_warn_battery                  ; Check if the battery level should be displayed/warned

	btfsc	FLAG_apnoe_mode             ; Done for Apnoe or Gauge mode
    bra     divemode_check_for_warnings2
	btfsc	FLAG_gauge_mode             ; Done for Apnoe or Gauge mode
	bra     divemode_check_for_warnings2

    ; Warnings only in deco modes
    btfss   FLAG_ccr_mode                       ; Don't check in CCR mode
	rcall	check_ppO2							; check ppO2 and displays warning, if required
    btfsc   is_bailout                          ; But check in Bailout case...
	rcall	check_ppO2							; check ppO2 and displays warning, if required
	rcall	check_cns_violation					; Check CNS value and display it, if required
	btfsc	decostop_active						; In deco mode?
	rcall	check_and_store_gf_violation		; Yes, Sets warnings, if required
	btfsc	decostop_active						; In deco mode?
    call    TFT_ftts                            ; Show @+x time
    btfsc   use_agf                             ; In aGF mode?
    rcall   warn_agf                            ; Yes, show a warning for it

divemode_check_for_warnings2:
; Display the warning icon?
	btfsc	warning_active				; Any warning active?
	call	TFT_divemode_warning				; Yes
	btfss	warning_active				; Any warning active?
	call	TFT_divemode_warning_clear			; No, clear warning icon

; Setup warning_page number
    incf    warning_page,F
    bcf     STATUS,C
    rlcf    warning_page,W                      ; *2
    cpfsgt  warning_counter                     ; > warning_counter
    clrf    warning_page                        ; No, clear

; Clear 2nd row of warnings if there is nothing to show (on this page)
    btfss   second_row_warning                  ; =1: The second row contains a warning
    call    TFT_clear_warning_text_2nd_row      ; No, clear this row
    return                                      ; Done.

    global  check_warn_battery
check_warn_battery:
    movff   batt_percent,lo
	movlw	battery_show_level+1
	cpfslt	lo
    return                              ; No Display, no warning
    ; Display Battery, but warn?
	incf	warning_counter,F			; increase counter
    call	TFT_update_batt_percent_divemode    ; Show percent

	movlw	color_code_battery_low+1
	cpfslt	lo                          ;
	return                              ; No warning
	bsf		warning_active		; Set Warning flag
	return

check_ppO2:							    ; check current ppO2 and display warning if required
    SAFE_2BYTE_COPY amb_pressure, xA
	movlw	d'10'
	movwf	xB+0
	clrf	xB+1
	call	div16x16				; xC=p_amb/10

	movff	xC+0,xA+0
	movff	xC+1,xA+1
    movff   char_I_O2_ratio,xB+0    ; =O2 ratio
	clrf	xB+1
	call	mult16x16               ; char_I_O2_ratio * p_amb/10

    ; Check very high ppO2 manually
	tstfsz	xC+2				; char_I_O2_ratio * p_amb/10 > 65536, ppO2>6,55bar?
	bra		check_ppO2_1		; Yes, display Value!
    ; Check if ppO2>3,30bar
	btfsc   xC+1,7
	bra     check_ppO2_1		; Yes!

    ; Check for low ppo2
    movff	xC+0,sub_b+0
	movff	xC+1,sub_b+1
    movff   opt_ppO2_min,WREG
	mullw	d'100'				; opt_ppO2_min*100
	movff	PRODL,sub_a+0
	movff	PRODH,sub_a+1
	call	subU16
	btfsc	neg_flag
	bra     check_ppO2_0        ; Not too low
    ; ppO2 low
	incf	warning_counter,F	; increase counter
	call	TFT_display_ppo2	; Show ppO2
	movlw	d'4'				; Type of Alarm (ppO2 low)
	movwf	AlarmType			; Copy to Alarm Register
	bsf		event_occured		; Set Event Flag
	bsf		warning_active		; Set Warning flag
	return						; Done.

check_ppO2_0:
    ; Check if ppO2 should be displayed
    movlw   ppo2_display_high
	mullw	d'100'				; ppo2_display_high*100
	movff	PRODL,sub_a+0
	movff	PRODH,sub_a+1
	call	subU16
	btfss	neg_flag
	return						; No Display, no warning
    ; Display ppO2, but warn?
	incf	warning_counter,F	; increase counter
	call	TFT_display_ppo2	; Show ppO2

;check if we are within our warning thresholds!
	movff	xC+0,sub_b+0
	movff	xC+1,sub_b+1
	movff	opt_ppO2_max,WREG	; PPO2 Max for MOD calculation and color coding in divemode
	mullw	d'100'				; opt_ppO2_max*100
	movff	PRODL,sub_a+0
	movff	PRODH,sub_a+1
	call	subU16					
	btfss	neg_flag
	return						; Done. Not too high
	movlw	d'5'				; Type of Alarm (ppO2 high)
	movwf	AlarmType			; Copy to Alarm Register
	bsf		event_occured		; Set Event Flag
	bsf		warning_active		; Set Warning flag
	return						; Done.

check_ppO2_1:                   ; ppO2 very high
	incf	warning_counter,F	; increase counter
	call	TFT_display_ppo2	; Show ppO2
	movlw	d'5'				; Type of Alarm
	movwf	AlarmType			; Copy to Alarm Register
	bsf		event_occured		; Set Event Flag
	bsf		warning_active		; Set Warning flag
	return						; Done.

    global  check_cns_violation
check_cns_violation:
    ; Check if CNS should be displayed
    movff   int_O_CNS_fraction+1,lo		; copy into bank1
    tstfsz  lo                          ; >255% ?
    bra     check_cns_violation2        ; Yes
	movff	int_O_CNS_fraction+0,lo		; copy into bank1

	movlw	cns_warning_high			; cns_warning_high
	subwf	lo,W
	btfsc	STATUS,C
	bsf		warning_active              ; Set Warning flag

	movlw	cns_display_high			; cns_display_high
	subwf	lo,W
	btfss	STATUS,C
	return                              ; No Display, no warning
    ; Display CNS
	incf	warning_counter,F			; increase counter
	call	TFT_display_cns				; Show CNS
	return

check_cns_violation2:
	incf	warning_counter,F			; increase counter
	call	TFT_display_cns				; Show CNS
	bsf		warning_active		; Set Warning flag
	return

    global  check_and_store_gf_violation
check_and_store_gf_violation:
	movff	char_O_gradient_factor,lo			; gradient factor absolute (Non-GF model)
	movff	char_I_deco_model,hi
	decfsz	hi,F		; jump over next line if char_I_deco_model == 1
	movff	char_O_relative_gradient_GF,lo		; gradient factor relative (GF model)

	movlw	gf_warning_high
	cpfsgt	lo
	bra     check_and_store_gf_violation2   ; No warning
	movlw	d'2'                        ; Type of Alarm
	movwf	AlarmType                   ; Copy to Alarm Register
	bsf		event_occured               ; Set Event Flag
	bsf		warning_active              ; Set Warning flag
check_and_store_gf_violation2:
	movlw	gf_display_high
	cpfsgt	lo
    return                              ; No Display, no warning
    ; Display GF
	incf	warning_counter,F			; increase counter
    call    TFT_warning_gf              ; Show GF Warning
	return

warn_agf:
	incf	warning_counter,F			; increase counter
	call	TFT_warning_agf             ; Show aGF warning
	bsf		warning_active              ; Set Warning flag
    return


 END