view src/options.asm @ 632:0347acdf6d8e

changelog updates
author heinrichsweikamp
date Sat, 29 Feb 2020 16:57:45 +0100
parents 185ba2f91f59
children 4050675965ea
line wrap: on
line source

;=============================================================================
;
;   File options.asm                          next combined generation V3.08.8
;
;   Manage all options data.
;
;   Copyright (c) 2011, JD Gascuel, HeinrichsWeikamp, all right reserved.
;=============================================================================
; HISTORY
;   2011-07-12 : [jDG] Creation.
;

#include "hwos.inc"							; mandatory header
#include "strings.inc"
#include "convert.inc"
#include "ghostwriter.inc"
#include "eeprom_rs232.inc"
#include "external_flash.inc"
#include "wait.inc"
#include "shared_definitions.h"
#include "gaslist.inc"

	extern	write_eeprom
	extern	read_eeprom
	extern	option_table_begin,option_table_end
	extern	convert_meter_to_feet

options		CODE

;=============================================================================
; Reset all options to factory defaults (in memory only)
;
; INPUT:  none
; OUTPUT: none
; TRASH:  TBLPTR, TABLAT, WREG, FSR0, FSR1, FSR2
;
	global	option_reset_all				; reset all options to factory default
option_reset_all:
	call	eeprom_total_dives_read			; read total number of dives
	tstfsz	mpr+0							; number of total dives, low  byte = 0 ?
	bra		option_reset_all_1				; NO - skip resetting logbook
	tstfsz	mpr+1							; number of total dives, high byte = 0 ?
	bra		option_reset_all_1				; NO - skip resetting logbook

	; reset logbook
	call	erase_complete_logbook			; erase complete logbook

	; reset logbook offset
	CLRI	mpr								; set   logbook offset to zero
	call	eeprom_log_offset_write			; store logbook offset

option_reset_all_1:
	lfsr	FSR0,option_table_begin			; point to start of option definition table
option_reset_all_loop:
	rcall	option_reset					; reset option
	incfsz	opt_end_token,F					; was this the last option (was opt_end_token = 255) ?
	bra		option_reset_all_loop			; NO  - do next option
	return									; YES - done


;=============================================================================
; Reset an option to its default value
; INPUT:  FSR0 = option handle
; OUTPUT: none
; TRASH:  TBLPTR, TABLAT, WREG, FSR1, FSR2
;
	global	option_reset					; reset option value to default
option_reset:
	; read type, default and register from table
	rcall	option_read_definition			; read option definition

option_reset_loaded:						; entry point with option definition already read
	bsf		option_repaired					; flag that an option was repaired
	bsf		options_changed					; flag that EEPROM needs to be updated
	movf	opt_type,W						; get option type
	xorlw	.2								; type = STRING ?
	bz		opt_reset_string				; YES - string copy
	movff	opt_default,INDF1				; NO  - 1 byte copy
	return									;     - done

opt_reset_string:
	movff	FSR1L,FSR2L						; set string destination address
	movff	FSR1H,FSR2H						; ...
	movff	opt_default+0,FSR1L				; get handle to multi-lingual text in FSR1
	movff	opt_default+1,FSR1H				; ...
	movff	TBLPTRL,mpr+0					; TBLPTR will be trashed by text routine, so make a back-up
	movff	TBLPTRH,mpr+1					; ...
	movff	TBLPTRU,mpr+2					; ...
	call	strcat_text						; copy translated text to FSR2
	movff	mpr+0,TBLPTRL					; restore TBLPTR
	movff	mpr+1,TBLPTRH					; ...
	movff	mpr+2,TBLPTRU					; ...
	return									; done


;=============================================================================
; Read option definition
; INPUT:  FSR0 = option handle
; OUTPUT: FSR1 = address of variable.
; TRASH:  TBLPTR, TABLAT, WREG, FSR0, FSR1
;
option_read_definition:
	movff	FSR0L,TBLPTRL					; low byte  : set memory address of option data set
	movlw	HIGH(option_table_begin)		; high byte : get table start address
	andlw	0xF0							;             keep only the upper nibble
	iorwf	FSR0H,W							;             add the memory address of the option data set
	movwf	TBLPTRH							;             set the resulting memory address
	movlw	UPPER(option_table_begin)		; upper byte: get table start address
	movwf	TBLPTRU							;             set memory address of option data set

	lfsr	FSR1,opt_type					; load FSR1 with base address of option definition vars
	movlw	opt_definiton_bytes				; get number of bytes to copy
	movwf	eeprom_loop						; initialize loop counter (using an EEPROM variable here)
option_read_definition_loop:
	tblrd*+									; read one byte from program memory and increment address
	movff	TABLAT,POSTINC1					; transfer byte from program memory to memory
	decfsz	eeprom_loop,F					; all bytes done?
	bra		option_read_definition_loop		; NO  - loop
	tblrd*									; YES - read one byte ahead without incrementing address
	movff	TABLAT,POSTINC1					;     - store byte
	movff	opt_memory+0,FSR1L				;     - load FSR1 with the address of the option value variable
	movff	opt_memory+1,FSR1H				;     - ...
	movff	TBLPTRL,FSR0L					;     - advance handle to the next option definition data set
	movff	TBLPTRH,FSR0H					;     - ...
	return									;     - done


;=============================================================================
; Check one option and reset its value if it is out of min/max boundary
; INPUT:  opt_* vars and FSR1
; OUTPUT: option value set to default if out of min/max
; TRASH:  WREG
;
option_check_loaded:
	; switch on type
	movf	opt_type,W						; get type
	bz		option_check_uint8				; type 0: INT8
	dcfsnz	WREG							; decrement
	bra		option_check_enum8				; type 1: ENUM
	dcfsnz	WREG							; decrement
	bra		option_check_string				; type 2: STRING
	;bra	option_check_uint8				; type 3: INT8

option_check_uint8:
	tstfsz	opt_min							; opt_min = 0 ?
	bra		option_check_min				; NO  - check it
	bra		option_check_enum8				; YES - continue with check for maximum

option_check_min:
	decf	opt_min,W						; get (minimum permissible value - 1) into WREG
	cpfsgt	INDF1							; option value > (minimum permissible value - 1) ?
	bra		option_reset_loaded				; NO  - reset option value
	;bra	option_check_enum8				; YES - continue with check for maximum

option_check_enum8:
	infsnz	opt_max,W						; get (highest permissible value + 1) into WREG
	return									; highest permissible value was 255, skip check, done
	cpfslt	INDF1							; option value < (highest permissible value + 1) ?
	bra		option_reset_loaded				; NO  - reset option value
	return									; YES - within range, done

option_check_string:
	return									; nothing to check with strings


;=============================================================================
; Check and store all option values in EEPROM
;
	global	option_check_and_store_all
option_check_and_store_all:
	bcf		PIR3,RC2IE						; disable EUSART interrupts

	;---- save option version
	MOVLI	eeprom_opt_version,mpr				; get   options version number
	EEPROM_II_WRITE mpr,eeprom_options_version	; store options version number in EEPROM

	;---- check and resolve some interdependencies among options
	bsf		is_diluent_menu					; setup checking diluents
	call	gaslist_cleanup_list			; check and correct multiple or none First diluents

	bcf		is_diluent_menu					; setup checking gases
	call	gaslist_cleanup_list			; check and correct multiple or none First gases

 IFNDEF _gauge_mode
	call	option_cleanup_gauge			; check and correct gauge mode
 ENDIF

 IFDEF _ccr_pscr
	call	option_cleanup_oCCRMode			; check and correct CCR / pSCR mode
 ENDIF

	call	option_cleanup_GF				; check and correct GFlow <= GFhigh

	;---- check and save all option values
	lfsr	FSR0,option_table_begin			; point to start of option definition table
option_save_all_loop:
	rcall	option_check_and_store			; check and save option value
	incfsz	opt_end_token,F					; was this the last option (was opt_end_token = 255) ?
	bra		option_save_all_loop			; NO  - do next option
	return									; YES - done


;=============================================================================
; Check and store an option value in EEPROM
;
	global	option_check_and_store
option_check_and_store:
	rcall	option_read_definition			; read the option definition
	rcall	option_check_loaded				; check if option value is within min/max, set to default if not

option_save_loaded_checked:
	movf	opt_eeprom_bank,W				; get bank
	andlw	b'11111110'						; keep only bits 7-1
	tstfsz	WREG							; bank < 0x02 ?
	return									; NO  - volatile option or illegal address, abort
	tstfsz	opt_eeprom_bank					; YES - bank = 0 ?
	bra		option_save_execute				;       NO  - address is valid
	movlw	low(eeprom_options_storage-1)	;       YES - get start address of options storage minus 1
	cpfsgt	opt_eeprom_index				;           - index >= start address ?
	return									;             NO  - illegal address, abort
	;bra	option_save_execute				;             YES - address is valid

option_save_execute:
	movff	opt_eeprom_index,EEADR			; set EEPROM index (address low  byte)
	movff	opt_eeprom_bank, EEADRH			; set EEPROM page  (address high byte)

	movf	opt_type,W						; get option type
	xorlw	.2								; option type = string ?
	bz		option_save_string				; YES - special handling
	movff	INDF1,EEDATA					; NO  - copy option value to EEPROM write register
	call	write_eeprom					;     - execute write
	return									;     - done

option_save_string:
	movff	POSTINC1,EEDATA					; copy a character from the option value to the EEPROM write register
	btfss	EEADRH,1						; current EEPROM address < 512 ?
	call	write_eeprom					; YES  - execute write
	infsnz	EEADR,F							; increment EEPROM address, low  byte
	incf	EEADRH,F						; increment EEPROM address, high byte
	decfsz	opt_max							; decrement string length, done?
	bra		option_save_string				; NO  - loop
	return									; YES - done


;=============================================================================
; Restore and check all option values from EEPROM
;
	global	option_restore_and_check_all	; restore options from EEPROM
option_restore_and_check_all:
	;---- Read option version from EEPROM
	EEPROM_II_READ	eeprom_options_version,mpr

	movlw	LOW(eeprom_opt_version)			; get options version from current firmware, low  byte
	xorwf	mpr+0,W							; compare with EEPROM version, do they match?
	bnz		option_restore_reset			; NO - reset to defaults of current firmware

	movlw	HIGH(eeprom_opt_version)		; get options version from current firmware, high byte
	xorwf	mpr+1,W							; compare with EEPROM version, do they match?
	bnz		option_restore_reset			; NO  - reset to defaults of current firmware

	;---- restore all option values
	lfsr	FSR0,option_table_begin			; point to start of option definition table
option_restore_all_loop:
	rcall	option_restore_and_check		; restore and check the option
	incfsz	opt_end_token,F					; was this the last option (was opt_end_token = 255) ?
	bra		option_restore_all_loop			; NO  - do next option
	return									; YES - done

option_restore_reset:
	call	option_reset_all				; reset all option values to their default
	goto	option_check_and_store_all		; write back all option values to EEPROM (and return)


;=============================================================================
; Restore an option value from EEPROM and check it
;
	global	option_restore_and_check
option_restore_and_check:
	rcall	option_read_definition			; read the option definition

	movf	opt_eeprom_bank,W				; get bank
	andlw	b'11111110'						; keep only bits 7-1
	tstfsz	WREG							; bank < 0x02 ?
	bra		option_reset_loaded				; NO  - volatile option or illegal address, restore to default
	tstfsz	opt_eeprom_bank					; YES - bank = 0 ?
	bra		option_restore_execute			;       NO  - address is valid
	movlw	low(eeprom_options_storage-1)	;       YES - get start address of options storage minus 1
	cpfsgt	opt_eeprom_index				;           - index >= start address ?
	bra		option_reset_loaded				;             NO  - illegal address, restore to default
	;bra	option_restore_execute			;             YES - address is valid

option_restore_execute:
	movff	opt_eeprom_index,EEADR			; set EEPROM index (address low  byte)
	movff	opt_eeprom_bank, EEADRH			; set EEPROM page  (address high byte)

	movf	opt_type,W						; get option type
	xorlw	.2								; option type = string ?
	bz		option_restore_string			; YES - special handling
	call	read_eeprom						; NO  - execute read
	movff	EEDATA,INDF1					;     - read option value from EEPROM read register
	bcf		option_repaired					;     - clear option repaired flag
	bra		option_check_loaded				;     - check if option value is within min/max, reset to default if not
	btfsc	option_repaired					;     - was the option repaired?
	bra		option_save_loaded_checked		;       YES - save repaired value to EEPROM
	return									;       NO  - done

option_restore_string:
	call	read_eeprom						; read one character from the EEPROM
	movff	EEDATA,POSTINC1					; copy it to the option value
	infsnz	EEADR,F							; increment EEPROM address, low  byte
	incf	EEADRH,F						; increment EEPROM address, high byte
	decfsz	opt_max							; decrement string length, done?
	bra		option_restore_string			; NO  - loop
	return									; YES - done (nothing to check with strings)



;=============================================================================
; Read an option value via RS232
; INPUT:  lo   = serial index
; OUTPUT: hi   = option value
;         WREG =0: option found and value valid, =1: option not found
; TRASH:  TBLPTR, TABLAT, WREG, FSR0, FSR1
;
	global	option_read_serial
option_read_serial:
	lfsr	FSR0,option_table_begin			; point to start of option definition table
option_read_serial_loop:
	rcall	option_read_definition			; read option definition
	movf	opt_serial,W					; get serial index of the option into WREG
	xorwf	lo,W							; received index = index of this option ?
	bz		option_read_serial_execute		; YES - read value
	incfsz	opt_end_token,F					; NO  - was this the last option (was opt_end_token = 255) ?
	bra		option_read_serial_loop			;       NO  - try next option
	retlw	.1								;       YES - done, option not found

option_read_serial_execute:
	movff	INDF1,hi						; read option value into hi
	retlw	.0								; done, option found


;=============================================================================
; Write an option value via RS232
; INPUT:  lo   = serial index
;         hi   = option value
; OUTPUT: WREG =0: option found and value valid, =1: option not found, =2: value not valid
; TRASH:  TBLPTR, TABLAT, WREG, FSR0, FSR1, up
;
	global	option_write_serial
option_write_serial:
	lfsr	FSR0,option_table_begin			; point to start of option definition table
option_write_serial_loop:
	rcall	option_read_definition			; read option definition
	movf	opt_serial,W					; get serial index of the option into WREG
	xorwf	lo,W							; received index = index of this option ?
	bz		option_write_serial_execute		; YES - check and update value
	incfsz	opt_end_token,F					; NO  - was this the last option (was opt_end_token = 255) ?
	bra		option_write_serial_loop		;       NO  - try next option
	retlw	.1								;       YES - done, option not found

option_write_serial_execute:
	movff	INDF1,up						; backup old value
	movff	hi,INDF1						; write  new value
	bcf		option_repaired					; clear option repaired flag
	rcall	option_check_loaded				; check the new value
	btfsc	option_repaired					; was   the new value valid?
	bra		option_write_serial_execute_fail; NO  - restore old value
	bsf		options_changed					; YES - flag that EEPROM needs to be updated
	retlw	.0								;     - done, success
option_write_serial_execute_fail:
	movff	up,INDF1						; restore old value
	retlw	.2								; done, value not valid


;=============================================================================
; Increment an option value based on type and min/max boundary
; INPUT:  FSR0 = option handle
; OUTPUT: none
; TRASH:  TBLPTR, TABLAT, WREG, FSR0, FSR1
;
	global	option_inc						; increment FSR0 option
option_inc:
	; read type, default and register from table
	rcall	option_read_definition

	bsf		options_changed					; flag that EEPROM needs to be updated

	; switch on type
	movf	opt_type,W						; get option type
	bz		option_inc_uint8				; type 0: INT8
	dcfsnz	WREG							; decrement
	bra		option_inc_enum8				; type 1: ENUM
	dcfsnz	WREG							; decrement
	bra		option_inc_string				; type 2: STRING
	;bra	option_inc_uint8				; type 3: INT8

option_inc_uint8:
	movf	INDF1,W							; get option value
	addwf	opt_inc,W						; add increment
	cpfslt	opt_max							; max < option value ?
	bra		option_inc_uint8_0				; NO  - new option value ok
	movf	opt_min,W						; YES - reset to min value
option_inc_uint8_0:
	movwf	INDF1							; store new value
option_inc_uint8_1:
	; now some rather crude hack into this routine to make CCR calibration more convenient:
	movlw	0x37							; serial ID of option CalGasO2
	cpfseq	opt_serial						; editing CalGasO2 right now?
	bra		option_inc_uint8_2				; NO - check next option
	movff	opt_dive_mode,WREG				; YES - get dive mode: 0=OC, 1=CC, 2=Gauge, 3=Apnea, 4=pSCR
	decfsz	WREG,W							;     - in CCR mode?
	return									;       NO  - done
	movlw	.26								;       YES -
	cpfseq	INDF1							;           - option value = 26 ?
	return									;             NO  - done
	movlw	.95								;             YES - advance it to 95
	movwf	INDF1							;                 - store it
	return
option_inc_uint8_2:
	movlw	0x25							; serial ID of option opt_GF_low
	cpfseq	opt_serial						; editing opt_GF_low right now?
	bra		option_inc_uint8_3				; NO - check next option
	movff	opt_GF_high,WREG				; get value of associated GF high into WREG
	cpfsgt	INDF1							; GF low > GF high?
	return									; NO  - setting ok, done
	movff	opt_min,INDF1					; YES - wrap around to minimum value
	return									;     - done
option_inc_uint8_3:
	movlw	0x26							; serial ID of option opt_GF_high
	cpfseq	opt_serial						; editing opt_GF_high right now?
	bra		option_inc_uint8_4				; NO - check next option
	movff	opt_GF_low,WREG					; get value of associated GF low into WREG
	cpfslt	INDF1							; GF high < GF low?
	return									; NO  - setting ok, done
	movwf	INDF1							; YES - rise GF high to GF low
	return									;     - done
option_inc_uint8_4:
	movlw	0x27							; serial ID of option opt_aGF_low
	cpfseq	opt_serial						; editing opt_aGF_low right now?
	bra		option_inc_uint8_5				; NO - check next option
	movff	opt_aGF_high,WREG				; get value of associated GF high into WREG
	cpfsgt	INDF1							; GF low > GF high?
	return									; NO  - setting ok, done
	movff	opt_min,INDF1					; YES - wrap around to minimum value
	return									;     - done
option_inc_uint8_5:
	movlw	0x28							; serial ID of option opt_aGF_high
	cpfseq	opt_serial						; editing opt_aGF_high right now?
	bra		option_inc_uint8_6				; NO - check next option
	movff	opt_aGF_low,WREG				; get value of associated GF low into WREG
	cpfslt	INDF1							; GF high < GF low?
	return									; NO  - setting ok, done
	movwf	INDF1							; YES - rise GF high to GF low
	return									;     - done
option_inc_uint8_6:
	return									; all done


option_inc_enum8:
	movf	opt_max,W						; copy maximum permissible value to WREG
	cpfslt	INDF1							; option value < maximum permissible value ?
	bra		option_inc_enum8_reset			; NO  - reset     option value
	incf	INDF1,F							; YES - increment option value
	bra		option_inc_enum8_1				;     - continue
option_inc_enum8_reset:
	clrf	INDF1							; reset option value to zero

option_inc_enum8_1:
 IFDEF _ccr_pscr
	; now some rather crude hack into this routine to unify CCR & pSCR mode setting
	movlw	0x1F							; serial ID of option oCCRMode
	cpfseq	opt_serial						; editing oCCRMode right now?
	bra		option_inc_enum8_2				; NO  - check next option
 IFDEF _external_sensor
	btfsc	analog_o2_input					; YES - does hosting OSTC have an analog interface?
	bra		option_inc_enum8_1a				;       YES - setting 'sensor' allowed
	btfsc	optical_input					;       does hosting OSTC have an optical interface?
	bra		option_inc_enum8_1a				;       YES - setting 'sensor' allowed
 ENDIF	; _external_sensor
	movf	INDF1,W							;       NO to both - get mode (=0: fixed SP, =1: Sensor, =2: AutoSP)
	xorlw	.1								;                  - in sensor mode?
	bnz		option_inc_enum8_1a				;                    NO  - continue with next check
	incf	INDF1,F							;                    YES - advance option value to AutoSP
option_inc_enum8_1a:
	movff	opt_dive_mode,WREG				; get dive mode: 0=OC, 1=CCR, 2=Gauge, 3=Apnea, 4=pSCR
	xorlw	.4								; in pSCR mode?
	bnz		option_inc_enum8_1_exit			; NO  - done
	bcf		INDF1,1							; YES - clear bit 1 because opt_ccr_mode may only be 0 or 1 (reverts AutoSP to calculated SP)
option_inc_enum8_1_exit:
	return									; done
 ENDIF	; _ccr_pscr

option_inc_enum8_2:
 IFDEF _gas_contingency
	; now some rather crude hack to switch off contingency mode if gas needs calculation is switched off
	movlw	0x5A							; serial ID of option opt_calc_gasvolume
	cpfseq	opt_serial						; editing opt_calc_gasvolume right now?
	bra		option_inc_enum8_3				; NO  - check next option
	movf	INDF1,W							; YES - get option value
;	xorlw	.0								;     - option value = off ?
	bnz		option_inc_enum8_2_exit			;       NO  - done
	clrf	WREG							;       YES - force contingency to be off, too
	movff	WREG,opt_gas_contingency_dive	;           - ...
option_inc_enum8_2_exit:
	return
 ENDIF	; _gas_contingency

option_inc_enum8_3:
	; now some rather crude hack to correct opt_TR_mode in dependency of opt_dive_mode
	movlw	0x20							; serial ID of option opt_dive_mode
	cpfseq	opt_serial						; editing opt_dive_mode right now?
	bra		option_inc_enum8_4				; NO  - check next option
	movf	INDF1,W							; YES - get option value: 0=OC, 1=CCR, 2=Gauge, 3=Apnea, 4=pSCR
	xorlw	.1								;       in CCR mode?
	bnz		option_inc_enum8_3a				;       NO  - in some other mode
 IFNDEF _ccr_pscr
	incf	INDF1,f							;       YES - no CCR mode compiled in, advance to gauge mode
	bra		option_inc_enum8_3a				;           - check if gauge mode is available
 ENDIF	; _ccr_pscr
 IFDEF _rx_functions
	global	option_cleanup_oTrMode_CCR		; embedded clean-up entry-point
option_cleanup_oTrMode_CCR:					; entry point from cleanup during restart
	movff	opt_TR_mode,WREG				; get TR mode
	xorlw	.2								; mode = 2 (ind.double)?
	bnz		option_inc_enum8_3_exit			; NO  - done
	bra		option_inc_enum8_3_reset		; YES - revert mode to 1 (on)
 ENDIF	; _rx_functions
option_inc_enum8_3a:						; any mode other than CCR
 IFNDEF _gauge_mode
	movf	INDF1,W							; get option value: 0=OC, 1=CCR, 2=Gauge, 3=Apnea, 4=pSCR
	xorlw	.2								; in Gauge mode?
	bnz		option_inc_enum8_3b				; NO  - in some other mode
	incf	INDF1,f							;       YES - no Gauge mode compiled in, advance to Apnea mode
	bra		option_inc_enum8_3_exit			;           - done (Apnea mode is always available)
 ENDIF	; _gauge_mode
option_inc_enum8_3b:
 IFNDEF _ccr_pscr
	movf	INDF1,W							; get option value: 0=OC, 1=CCR, 2=Gauge, 3=Apnea, 4=pSCR
	xorlw	.4								; in pSCR mode?
	bnz		option_inc_enum8_3c				; NO  - in some other mode
	clrf	INDF1							; YES - no pSCR mode compiled in, advance to 0 "OC"
	bra		option_inc_enum8_3_exit			;     - done
 ENDIF	; _ccr_pscr
option_inc_enum8_3c:
	global	option_cleanup_oTrMode_no_CCR	; embedded clean-up entry-point
option_cleanup_oTrMode_no_CCR:				; entry point from cleanup during restart
	movff	opt_TR_mode,WREG				; get TR mode
	xorlw	.3								; mode = 3 (CCR Dil+O2)?
	bnz		option_inc_enum8_3_exit			; NO  - done
option_inc_enum8_3_reset:					; YES - revert to mode 1 (on)
	movlw	.1								; load coding of mode "on"
	movff	WREG,opt_TR_mode				; write to option
option_inc_enum8_3_exit:
	return									; done

option_inc_enum8_4:
 IFDEF _rx_functions
	; now some rather crude hack to advance opt_TR_mode in dependency of opt_dive_mode
	movlw	0x7E							; serial ID of option opt_TR_mode
	cpfseq	opt_serial						; editing opt_TR_mode right now?
	bra		option_inc_enum8_5				; NO  - check next option
	movff	opt_dive_mode,WREG				; YES - get dive mode: 0=OC, 1=CCR, 2=Gauge, 3=Apnea, 4=pSCR
	decfsz	WREG,W							;       dive mode = 1 CCR?
	bra		option_inc_enum8_4a				;       NO  - in any other mode
	movf	INDF1,W							;       YES - get option value (TR mode)
	xorlw	.2								;           - mode = 2 (ind.double)?
	bnz		option_inc_enum8_4_exit			;             NO  - done
	incf	INDF1,F							;             YES - advance option value to 3 (CCR Dil+O2)
	bra		option_inc_enum8_4_exit			;                 - done
option_inc_enum8_4a:						; any mode other than CCR
	movf	INDF1,W							; get option value (TR mode)
	xorlw	.3								; mode = 3 (CCR Dil+O2)?
	bnz		option_inc_enum8_4_exit			; NO  - done
	clrf	INDF1							; YES - advance option value to 0 "off"
option_inc_enum8_4_exit:
	return									; done
 ENDIF	; _rx_functions

option_inc_enum8_5:
 IFDEF _gas_contingency
	; now some rather crude hack to keep contingency mode switched off if gas needs calculation is switched off
	movlw	0x91							; serial ID of option opt_gas_contingency_dive
	cpfseq	opt_serial						; editing opt_gas_contingency_dive right now?
	bra		option_inc_enum8_6				; NO  - check next option
	movff	opt_calc_gasvolume,WREG			; YES - get current setting of gas needs calculation
	tstfsz	WREG							;     - gas needs calculation switched off?
	return									;       NO  - done, opt_gas_contingency_dive may be switched on
	clrf	INDF1							;       YES - force opt_gas_contingency_dive to off
	return									;           - done
 ENDIF	; _gas_contingency

option_inc_enum8_6:
	return


option_inc_string:							; no editing available
	return


 IFNDEF _gauge_mode
option_cleanup_gauge:
	movff	opt_dive_mode,WREG				; get dive mode into WREG (0=OC, 1=CCR, 2=Gauge, 3=Apnea, 4=pSCR)
	xorlw	.2								; in Gauge mode?
	bnz		option_cleanup_gauge_1			; NO  - done
	movff	WREG,opt_dive_mode				; YES - setting not allowed, WREG is zero -> reset to OC mode
	bsf		options_changed					;     - flag that EEPROM needs to be updated
option_cleanup_gauge_1:
	return									; done
 ENDIF


 IFDEF _ccr_pscr
	global	option_cleanup_oCCRMode
	global	option_cleanup_oCCRMode_pSCR
	global	option_cleanup_oCCRMode_CCR
option_cleanup_oCCRMode:					; in pSCR mode, revert AutoSP (2) to calculated SP (0), in pSCR and CCR revert Sensor to fixed SP if no sensor interface available
	movff	opt_dive_mode,WREG				; get dive mode into WREG (0=OC, 1=CCR, 2=Gauge, 3=Apnea, 4=pSCR)
	xorlw	.4								; in pSCR mode?
	bnz		option_cleanup_oCCRMode_CCR		; NO  - check if sensor is available on hosting OSTC
option_cleanup_oCCRMode_pSCR:				; jump-in from start.asm if known to be in pSCR mode
	banksel	opt_ccr_mode					; YES - select options bank
	bcf		opt_ccr_mode,1					;     - clear bit 1 because opt_ccr_mode may only be 0 or 1 (reverts AutoSP to calculated SP, keeps sensor)
	banksel	common							;     - back to bank common
	bsf		options_changed					;     - flag that EEPROM needs to be updated
option_cleanup_oCCRMode_CCR:				; continue from above & jump-in from start.asm if known to be in CCR mode
 IFDEF _external_sensor
	btfsc	analog_o2_input					; analog interface available?
	return									; YES - setting 'sensor' allowed
	btfsc	optical_input					; does hosting OSTC have an optical interface?
	return									; YES - setting 'sensor' allowed
 ENDIF
	movff	opt_ccr_mode,WREG				; NO to both - get CCR mode
	xorlw	.1								;            - coding for sensor
	tstfsz	WREG							;            - CCR mode = sensor?
	return									;              NO  - setting allowed
	banksel	opt_ccr_mode					;              YES - setting not allowed, select options bank
	clrf	opt_ccr_mode					;                  - revert setting to 0 (fixed or calculated SP)
	banksel	common							;                  - back to bank common
	bsf		options_changed					;                  - flag that EEPROM needs to be updated
	return									;                  - done
 ENDIF	; _ccr_pscr


option_cleanup_GF:
	; cleanup normal GF
	movff	opt_GF_high,WREG				; copy normal GF high to WREG
	movff	opt_GF_low,mpr					; copy normal GF low  to mpr
	cpfsgt	mpr								; GF low > GF high ?
	bra		option_cleanup_GF_2				; NO  - option ok, check next option
	movwf	mpr								; YES - copy GF high to mpr
	movlw	.100							;     - load GF low limit of 100% into WREG
	cpfsgt	mpr								;     - mpr > 100 ?
	bra		option_cleanup_GF_1				;       NO  - correct GF low to GF high
	movwf	mpr								;       YES - correct GF low to 100%
option_cleanup_GF_1:
	movff	mpr,opt_GF_low					; store corrected GF low
	bsf		options_changed					; flag that EEPROM needs to be updated
option_cleanup_GF_2:
	; cleanup alternative GF
	movff	opt_aGF_high,WREG				; copy alternative GF high to WREG
	movff	opt_aGF_low,mpr					; copy alternative GF low  to mpr
	cpfsgt	mpr								; GF low > GF high ?
	bra		option_cleanup_GF_4				; NO  - option ok, check next option
	movwf	mpr								; YES - copy GF high to mpr
	movlw	.100							;     - load GF low limit of 100% into WREG
	cpfsgt	mpr								;     - mpr > 100 ?
	bra		option_cleanup_GF_3				;       NO  - correct GF low to GF high
	movwf	mpr								;       YES - correct GF low to 100%
option_cleanup_GF_3:
	movff	mpr,opt_aGF_low					; store corrected GF low
	bsf		options_changed					; flag that EEPROM needs to be updated
option_cleanup_GF_4:
	return									; done


;=============================================================================
; Strcat option into FSR2 buffer
;
	global	option_draw						; STRCAT FRS0 option
option_draw:
	; read type, default and register from table
	rcall	option_read_definition

	; switch on type
	movf	opt_type,W						; get option type
	bz		option_draw_uint8				; type0 = INT8
	dcfsnz	WREG
	bra		option_draw_enum8				; type1 = ENUM
	dcfsnz	WREG
	bra		option_draw_string				; type2 = string
	dcfsnz	WREG
	bra		option_draw_uint8_depth			; type3 = INT8 with automatic display in meters or feet
	return									; unknown, do nothing

option_draw_string:
	movff	POSTINC1,POSTINC2
	decfsz	opt_max
	bra		option_draw_string
	return

option_draw_uint8_depth:
	TSTOSS	opt_units						; using metric units (0=m, 1=ft)?
	bra		option_draw_uint8				; YES - handle with standard output
	movff	INDF1,lo						; NO  - imperial, get value to lo
	call	convert_meter_to_feet			;     - convert value in lo from meter to feet
	bsf		leftbind						;     - print with left alignment
	output_16_3								;     - display only last three digits from a 16 bit value (0-999)
	bcf		leftbind						;     - back to normal alignment
	STRCAT_TEXT	tFeets						;     - print unit
	bra		option_draw_uint8_common		;     - continue with common part

option_draw_uint8:
	movff	INDF1,lo						; draw value
	bsf		leftbind
	output_8
	bcf		leftbind
	clrf	INDF2							; make sure to close string
	movf	opt_unit+0,W					; is there a unit to append?
	iorwf	opt_unit+1,W
	rcall	option_draw_unit				; YES
option_draw_uint8_common:
	movf	opt_default,W					; get default value
	cpfseq	lo								; compare with current value, equal?
	bra		option_draw_uint8_2				; NO  - not default, add *
	return									; YES - default, done
option_draw_uint8_2:
	PUTC	"*"								; print "*"
	return									; done

option_draw_unit:
	movff	opt_unit+0,FSR1L
	movff	opt_unit+1,FSR1H
	goto	strcat_text


;---- Draw an enumerated value (set of translated strings)
option_draw_enum8:
	movf	INDF1,W							; copy option value to WREG
	movwf	lo								; memorize option value, too
	cpfslt	opt_max							; option value > maximum permissible value ?
	bra		option_draw_enum8_0				; NO  - option value allowed
	clrf	WREG							; YES - to avoid printing rubbish, use first ENUM item instead
option_draw_enum8_0:
	addwf	WREG							; current value *= 2
	addwf	opt_inc,W						; base text + 2 * current value
	movwf	FSR1L							; load FSR1
	movlw	.0								; propagate carry...
	addwfc	opt_min,W						; ...
	movwf	FSR1H							; ...into FSR1
	call	strcat_text						; print text
	movf	opt_default,W					; get default value
	cpfseq	lo								; compare with memorized current value, equal?
	bra		option_draw_enum8_1				; NO  - not default, add *
	return									; YES - default, done
option_draw_enum8_1:
	PUTC	"*"								; print "*"
	return									; done

;-----------------------------------------------------------------------------

	END