diff src/options.asm @ 634:4050675965ea

3.10 stable release
author heinrichsweikamp
date Tue, 28 Apr 2020 17:34:31 +0200
parents 185ba2f91f59
children 070528a88715
line wrap: on
line diff
--- a/src/options.asm	Thu Mar 05 15:06:14 2020 +0100
+++ b/src/options.asm	Tue Apr 28 17:34:31 2020 +0200
@@ -1,6 +1,6 @@
 ;=============================================================================
 ;
-;   File options.asm                          next combined generation V3.08.8
+;   File options.asm                        * next combined generation V3.09.4n
 ;
 ;   Manage all options data.
 ;
@@ -25,10 +25,64 @@
 	extern	option_table_begin,option_table_end
 	extern	convert_meter_to_feet
 
-options		CODE
 
 ;=============================================================================
-; Reset all options to factory defaults (in memory only)
+options1	CODE
+;=============================================================================
+
+
+;-----------------------------------------------------------------------------
+; Adjust Address in FSR0 to an Option within an Option Group
+;
+; INPUT:  FSR0        = base address of the option group
+;         gaslist_gas = offset of the selected option within the group
+; OUTPUT: FSR0        = pointing to selected option
+;
+	global	option_adjust_group_member
+option_adjust_group_member:
+	movf	gaslist_gas,W					; get       offset in number of options
+	mullw	opt_definition_bytes			; calculate offset in number of bytes
+	movf	PRODL,W							; get number of bytes, low  byte
+	addwf	FSR0L,F							; add to FSR0,         low  byte
+	movf	PRODH,W							; get number of bytes, high byte
+	addwfc	FSR0H,F							; add to FSR0,         high byte
+	return									; done
+
+
+;-----------------------------------------------------------------------------
+; Read the Option Definition
+;
+; INPUT:  FSR0 = option handle
+; OUTPUT: FSR1 = address of variable.
+; TRASH:  TBLPTR, TABLAT, WREG, FSR0, FSR1
+;
+option_read_definition:
+	; option_table_begin is at 0x0|80|00
+	clrf	TBLPTRU							; TBLPRT upper = 0x00
+	movlw	HIGH(option_table_begin)		; TBLPRT high  = 0x80
+	iorwf	FSR0H,W							;              + 0x0H from FSR0H
+	movwf	TBLPTRH							;            set 0x8H
+	movff	FSR0L,TBLPTRL					; TBLPRT low   = 0xLL from FSR0L
+	; copy option definition from program to data memory
+	lfsr	FSR1,opt_type					; load FSR1 with base address of option definition buffer
+	movlw	opt_definition_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
+
+
+;-----------------------------------------------------------------------------
+; Reset all Options to Factory Defaults
 ;
 ; INPUT:  none
 ; OUTPUT: none
@@ -58,87 +112,74 @@
 	return									; YES - done
 
 
-;=============================================================================
-; Reset an option to its default value
+;-----------------------------------------------------------------------------
+; Reset an Option to its default Value
+;
 ; INPUT:  FSR0 = option handle
-; OUTPUT: none
+; OUTPUT: option value set to default value
+;         option_repaired flag set
+;         option_changed flag set if not a volatile option
 ; 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
+	btfss	opt_eeprom_bank,7				; volatile option?
+	bsf		option_changed					; NO  - flag that EEPROM needs to be updated
+	;bra	option_init_loaded				; continue initializing the option value
 
-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
+
+;-----------------------------------------------------------------------------
+; Reset an Option to its default Value
+;
+; INPUT:  opt_* option definition vars initialized
+; OUTPUT: option value set to default value
+; TRASH:  TBLPTR, TABLAT, WREG, FSR1, FSR2
+;
+option_init_loaded:
 	movf	opt_type,W						; get option type
 	xorlw	.2								; type = STRING ?
-	bz		opt_reset_string				; YES - string copy
+	bz		opt_init_loaded_string			; YES - string copy
 	movff	opt_default,INDF1				; NO  - 1 byte copy
 	return									;     - done
 
-opt_reset_string:
+opt_init_loaded_string:
+	movff	TBLPTRL,mpr+0					; back-up TBLPTR
+	movff	TBLPTRH,mpr+1					; ...
+	movff	TBLPTRU,mpr+2					; ...
+
 	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	opt_inc,FSR1L					; get pointer to multi-lingual default text (stored in opt_inc:opt_min)
+	movff	opt_min,FSR1H					; ...
+	call	strcat_text_FSR					; copy translated text to FSR2, hence string option
+
 	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
+;-----------------------------------------------------------------------------
+; Check one Option and reset its Value if it is out of its min/max Limits
 ;
-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
+; INPUT:  opt_* vars loaded, FSR1 pointing to option value
+;         hi    value to be checked for validity
+; OUTPUT: option_value_ok set/not set
 ; TRASH:  WREG
 ;
+	global	option_check_loaded
 option_check_loaded:
 	; switch on type
+	bsf		option_value_ok					; set result to ok by default
 	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
+	return									; type 2: STRING - nothing to check
 	;bra	option_check_uint8				; type 3: INT8
 
 option_check_uint8:
@@ -148,104 +189,117 @@
 
 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
+	cpfsgt	hi								; option value > (minimum permissible value - 1) ?
+	bra		option_check_nok				; NO  - value not ok
 	;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
+	return									; highest permissible value is 255, skip check, done
+	cpfslt	hi								; option value < (highest permissible value + 1) ?
+	bra		option_check_nok				; NO  - value not ok
+	return									; YES - value ok, done
 
-option_check_string:
-	return									; nothing to check with strings
+option_check_nok:
+	bcf		option_value_ok					; flag option value is invalid
+	return									; done
 
 
-;=============================================================================
-; Check and store all option values in EEPROM
+;-----------------------------------------------------------------------------
+; Check and store all Option Values to EEPROM
 ;
 	global	option_check_and_store_all
 option_check_and_store_all:
-	bcf		PIR3,RC2IE						; disable EUSART interrupts
+	bcf		PIR3,RC2IE						; disable EUSART interrupts								TODO: why???
+	call	option_crosschecks				; do some crosschecks between option values
+	;bra	option_store_all				; continue storing all option values to EEPROM
+
 
-	;---- save option version
+;-----------------------------------------------------------------------------
+; Store all Option Values to EEPROM
+;
+option_store_all:
+	;---- invalidate option version while updating
+	CLRI	mpr									; set options version number to zero
+	EEPROM_II_WRITE mpr,eeprom_options_version	; store options version number in EEPROM
+
+	;---- check and store 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 store 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
+
+	;---- store 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
+	bcf		option_changed					; no pending EEPROM updates any more
+	return									; done
 
 
-;=============================================================================
-; Check and store an option value in EEPROM
+;-----------------------------------------------------------------------------
+; Check and store one Option Value to 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
+	movff	INDF1,hi						; check current option value
+	rcall	option_check_loaded				; check value for validity
+	btfss	option_value_ok					; value ok (strings are always 'valid') ?
+	movff	opt_default,INDF1				; NO  - set value to default
+	;bra	option_store_loaded				; continue storing value
 
-option_save_loaded_checked:
+
+;-----------------------------------------------------------------------------
+; Store one Option Value to EEPROM
+;
+	global	option_store_loaded
+option_store_loaded:
 	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
+	return									; NO  - volatile option or illegal address, done/abort
 	tstfsz	opt_eeprom_bank					; YES - bank = 0 ?
-	bra		option_save_execute				;       NO  - address is valid
+	bra		option_store_execute			;       NO  - address is valid in any case
 	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
+	return									;             NO  - illegal address, done
+	;bra	option_store_execute			;             YES - address is valid
 
-option_save_execute:
+option_store_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
+	bz		option_store_exec_string		; YES - store string of bytes
+	;bnz	option_store_exec_byte			; NO  - store single    byte
 
-option_save_string:
-	movff	POSTINC1,EEDATA					; copy a character from the option value to the EEPROM write register
+option_store_exec_byte:
+	call	read_eeprom						; read stored value
+	movf	EEDATA,W						; copy stored value to WREG
+	xorwf	INDF1,W							; xor with current value
+	btfsc	STATUS,Z						; equal?
+	return									; YES - no need to write to EEPROM, done
+	movff	INDF1,EEDATA					; NO  - copy current option value to EEPROM write register
+	goto	write_eeprom					;     - execute write and return
+
+option_store_exec_string:
 	btfss	EEADRH,1						; current EEPROM address < 512 ?
-	call	write_eeprom					; YES  - execute write
+	rcall	option_store_exec_byte			; YES - store one byte from the string
+	movf	POSTINC1,W						; increment FSR1   address by a dummy read
 	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
+	bra		option_store_exec_string		; NO  - loop
 	return									; YES - done
 
 
-;=============================================================================
-; Restore and check all option values from EEPROM
+;-----------------------------------------------------------------------------
+; Restore all Option Values from EEPROM and check them
 ;
-	global	option_restore_and_check_all	; restore options from EEPROM
+	global	option_restore_and_check_all
 option_restore_and_check_all:
 	;---- Read option version from EEPROM
 	EEPROM_II_READ	eeprom_options_version,mpr
@@ -264,15 +318,20 @@
 	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
+
+	bcf		option_changed					; clear flag
+	call	option_crosschecks				; do some crosschecks between option values
+	btfsc	option_changed					; found and corrected errors?
+	bra		option_store_all				; YES - write back corrected data to EEPROM
+	return									; NO  - 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
+;-----------------------------------------------------------------------------
+; Restore one Option Value from EEPROM and check it
 ;
 	global	option_restore_and_check
 option_restore_and_check:
@@ -281,12 +340,12 @@
 	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
+	bra		option_init_loaded				; NO  - volatile option or illegal address, initialize to default
 	tstfsz	opt_eeprom_bank					; YES - bank = 0 ?
-	bra		option_restore_execute			;       NO  - address is valid
+	bra		option_restore_execute			;       NO  - address is valid in any case
 	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_init_loaded				;             NO  - illegal address, initialize to default
 	;bra	option_restore_execute			;             YES - address is valid
 
 option_restore_execute:
@@ -295,28 +354,31 @@
 
 	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
+	bz		option_restore_exec_string		; YES - special handling
+	call	read_eeprom						; NO  - execute   EEPROM read
+	movff	EEDATA,INDF1					;     - copy from EEPROM read register to option variable
+	movff	EEDATA,hi						;     - check loaded option value
+	rcall	option_check_loaded				;     - check if option value is within min/max limits
+	btfsc	option_value_ok					;     - option value ok (strings will always be 'ok') ?
+	return									;       YES  - done
+	movff	opt_default,INDF1				;       NO   - set option value to default
+	movff	INDF1,EEDATA					;            - copy repaired value to EEPROM write register
+	goto	write_eeprom					;            - execute write and return
 
-option_restore_string:
+option_restore_exec_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
+	bra		option_restore_exec_string		; NO  - loop
 	return									; YES - done (nothing to check with strings)
 
 
 
-;=============================================================================
-; Read an option value via RS232
+;-----------------------------------------------------------------------------
+; Read an Option Value via serial Index
+;
 ; INPUT:  lo   = serial index
 ; OUTPUT: hi   = option value
 ;         WREG =0: option found and value valid, =1: option not found
@@ -332,15 +394,16 @@
 	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
+	retlw	.1								;       YES - option not found, abort
 
 option_read_serial_execute:
 	movff	INDF1,hi						; read option value into hi
-	retlw	.0								; done, option found
+	retlw	.0								; done
 
 
-;=============================================================================
-; Write an option value via RS232
+;-----------------------------------------------------------------------------
+; Write an Option Value via serial Index
+;
 ; INPUT:  lo   = serial index
 ;         hi   = option value
 ; OUTPUT: WREG =0: option found and value valid, =1: option not found, =2: value not valid
@@ -356,52 +419,59 @@
 	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
+	retlw	.1								;       YES - option not found, abort
 
 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
+	rcall	option_check_loaded				; check if new value is valid
+	btfss	option_value_ok					; value valid?
+	retlw	.2								; NO  - value not valid, abort
+	movff	hi,INDF1						; YES - take new value
+	btfss	opt_eeprom_bank,7				;     - volatile option?
+	bsf		option_changed					;       NO  - flag that EEPROM needs to be updated
+	retlw	.0								;     - done
 
 
-;=============================================================================
-; Increment an option value based on type and min/max boundary
+;-----------------------------------------------------------------------------
+; Increment an Option Value based on Type and min/max Boundary
+;
 ; INPUT:  FSR0 = option handle
-; OUTPUT: none
+; OUTPUT: incremented option value
 ; TRASH:  TBLPTR, TABLAT, WREG, FSR0, FSR1
 ;
-	global	option_inc						; increment FSR0 option
+	global	option_inc
 option_inc:
 	; read type, default and register from table
 	rcall	option_read_definition
 
-	bsf		options_changed					; flag that EEPROM needs to be updated
+	btfss	opt_eeprom_bank,7				; volatile option?
+	bsf		option_changed					; NO  - flag that EEPROM needs to be updated
 
 	; switch on type
 	movf	opt_type,W						; get option type
-	bz		option_inc_uint8				; type 0: INT8
+	bz		option_inc_uint8				; type 0: UINT8
 	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
+	return									; type 2: STRING - no inc function defined
+	dcfsnz	WREG							; decrement
+	bra		option_inc_uint8				; type 3: UINT8 as meters or feet
+	return									; unknown, do nothing
 
+
+;-----------------------------------------------------------------------------
+; Helper Function - increment UINT8, wrap-around or stop at option max
+;
 option_inc_uint8:
 	movf	INDF1,W							; get option value
 	addwf	opt_inc,W						; add increment
-	cpfslt	opt_max							; max < option value ?
+	cpfslt	opt_max							; option value > max ?
 	bra		option_inc_uint8_0				; NO  - new option value ok
-	movf	opt_min,W						; YES - reset to min value
+	movf	opt_min,W						; YES - reset to min value by default
+	btfsc	option_stop_at_max				;     - shall the option value stop at max?
+	movf	opt_max,W						;       YES - keep at max value
 option_inc_uint8_0:
 	movwf	INDF1							; store new value
+	; do cross-checks with other option values
 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
@@ -416,7 +486,9 @@
 	movlw	.95								;             YES - advance it to 95
 	movwf	INDF1							;                 - store it
 	return
+
 option_inc_uint8_2:
+	; check GF low <= GF high
 	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
@@ -425,7 +497,9 @@
 	return									; NO  - setting ok, done
 	movff	opt_min,INDF1					; YES - wrap around to minimum value
 	return									;     - done
+
 option_inc_uint8_3:
+	; check GF high >= GF low
 	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
@@ -434,7 +508,9 @@
 	return									; NO  - setting ok, done
 	movwf	INDF1							; YES - rise GF high to GF low
 	return									;     - done
+
 option_inc_uint8_4:
+	; check aGF low <= aGF high
 	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
@@ -443,7 +519,9 @@
 	return									; NO  - setting ok, done
 	movff	opt_min,INDF1					; YES - wrap around to minimum value
 	return									;     - done
+
 option_inc_uint8_5:
+	; check aGF high >= aGF low
 	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
@@ -452,19 +530,60 @@
 	return									; NO  - setting ok, done
 	movwf	INDF1							; YES - rise GF high to GF low
 	return									;     - done
+
 option_inc_uint8_6:
+	; progressive increment for char_I_SAC_work
+	movlw	0x3C							; serial ID of option char_I_SAC_work
+	cpfseq	opt_serial						; editing char_I_SAC_work right now?
+	bra		option_inc_uint8_7				; NO  - check next option
+	movlw	.40								; YES - set threshold for incrementing in steps of 2
+	cpfsgt	INDF1							;     - option value > threshold ?
+	return									;       NO  - done
+	incf	INDF1,F							;       YES - increment one more time
+	return									;           - done
+
+option_inc_uint8_7:
+ IFDEF _helium
+	; check O2% + He% <= 100%
+	movlw	0xFA							; serial ID of O2% options
+	cpfseq	opt_serial						; editing a O2% right now?
+	bra		option_inc_uint8_7a				; NO  - check for He%
+	movlw	.2*NUM_GAS						; YES - load offset between O2% and He% for gas/dil 1-5
+	btfsc	opt_eeprom_bank,7				;     - volatile option?
+	movlw	.1								;       YES - load offset between O2% and He% for gas 6
+	bra		option_inc_uint8_7b				;       continue with common part
+option_inc_uint8_7a:
+	movlw	0xFB							; serial ID of He% options
+	cpfseq	opt_serial						; editing a He% right now?
+	bra		option_inc_uint8_8				; NO  - check next option
+	movlw	-.2*NUM_GAS						; YES - load offset between He% and O2% for gas/dil 1-5
+	btfsc	opt_eeprom_bank,7				;     - volatile option?
+	movlw	-.1								;       YES - load offset between He% and O2% for gas 6
+option_inc_uint8_7b:
+	movff	PLUSW1,hi						;     - copy complementing gas % to hi
+	movf	INDF1,W							;     - copy primary       gas % to WREG
+	addwf	hi,F							;     - hi = O2% + He%
+	movlw	.101							;     - load max allowed sum + 1
+	cpfslt	hi								;     - O2% + He% < 101 ?
+	decf	INDF1,F							;       NO - decrement primary gas% again
+ ENDIF	; _helium
+
+option_inc_uint8_8
+	; add more cross-checks with other option values here
 	return									; all done
 
 
+;-----------------------------------------------------------------------------
+; Helper Function - increment ENUM, will wrap-around on exceeding option max
+;
 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
-
+	incf	INDF1,W							; get incremented option value
+	cpfslt	opt_max							; option value > max?
+	bra		option_inc_enum8_0				; NO  - new option value ok
+	clrf	WREG							; YES - reset to 1st option value
+option_inc_enum8_0:
+	movwf	INDF1							; store new value
+	; do cross-checks with other option values
 option_inc_enum8_1:
  IFDEF _ccr_pscr
 	; now some rather crude hack into this routine to unify CCR & pSCR mode setting
@@ -472,9 +591,9 @@
 	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?
+	btfsc	ext_input_s8_ana				; YES - S8/analog input available?
 	bra		option_inc_enum8_1a				;       YES - setting 'sensor' allowed
-	btfsc	optical_input					;       does hosting OSTC have an optical interface?
+	btfsc	ext_input_optical				;     - optical interface available?
 	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)
@@ -497,7 +616,7 @@
 	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 ?
+	;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	;           - ...
@@ -590,57 +709,208 @@
  ENDIF	; _gas_contingency
 
 option_inc_enum8_6:
-	return
-
-
-option_inc_string:							; no editing available
+	; add more cross-checks with other option values here
 	return
 
 
+;-----------------------------------------------------------------------------
+; Decrement an Option Value based on Type and min/max Boundary
+;
+; INPUT:  FSR0 = option handle
+; OUTPUT: decremented option value
+; TRASH:  TBLPTR, TABLAT, WREG, FSR0, FSR1
+;
+	global	option_dec
+option_dec:
+	; read type, default and register from table
+	rcall	option_read_definition
+
+	btfss	opt_eeprom_bank,7				; volatile option?
+	bsf		option_changed					; NO  - flag that EEPROM needs to be updated
+
+	; switch on type
+	movf	opt_type,W						; get option type
+	bz		option_dec_uint8				; type 0: UINT8
+	dcfsnz	WREG							; decrement
+	bra		option_dec_enum8				; type 1: ENUM
+	dcfsnz	WREG							; decrement
+	return									; type 2: STRING  - no dec function defined
+	dcfsnz	WREG							; decrement
+	bra		option_dec_uint8				; type 3: UINT8 as meters or feet
+	return									; unknown, do nothing
+
+
+;-----------------------------------------------------------------------------
+; Helper Function - decrement UINT8, will stop on reaching option min
+;
+option_dec_uint8:
+	movf	INDF1,W							; get option value
+	bsf		STATUS,C						; set carry (= clear borrow)
+	subfwb	opt_inc,W						; subtract increment
+	bnc		option_dec_uint8_reset			; under-run? -> reset
+	cpfsgt	opt_min							; option value < min ?
+	bra		option_dec_uint8_0				; NO  - new option value ok
+option_dec_uint8_reset:
+	movf	opt_min,W						; YES - reset to min value
+option_dec_uint8_0:
+	movwf	INDF1							; store new value
+	; add cross-checks with other option values here
+	return									; done
+
+
+;-----------------------------------------------------------------------------
+; Helper Function - decrement ENUM, will stop on reaching first option value
+;
+option_dec_enum8:
+	tstfsz	INDF1							; option value = 0 ?
+	decf	INDF1,F							; NO - decrement value
+option_dec_enum8_0:
+	; add cross-checks with other option values here
+	return									; done
+
+
+;-----------------------------------------------------------------------------
+; Draw an Option Value
+;
+	global	option_draw
+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 as meters or feet
+	return									; unknown, do nothing
+
+
+;-----------------------------------------------------------------------------
+; Helper Function - draw a String
+;
+option_draw_string:
+	movff	POSTINC1,POSTINC2				; copy one character
+	decfsz	opt_max							; decrement remaining string length, became zero?
+	bra		option_draw_string				; NO  - loop
+	return									; YES - done
+
+
+;-----------------------------------------------------------------------------
+; Helper Function - draw an INT with automatic display in meters or feet
+;
+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_999								;     - print depth (0-999)
+	STRCAT_TEXT	tFeets						;     - append unit and dump to screen
+	bra		option_draw_uint8_common		;     - continue with common part
+
+
+;-----------------------------------------------------------------------------
+; Helper Function - draw an INT
+;
+option_draw_uint8:
+	movff	INDF1,lo						; get option value
+
+	movlw	.99								; load a 99
+	cpfsgt	opt_max							; max value > 99 ?
+	bsf		hide_digit3						; NO - do not show digit 3
+	movlw	.9								; load a 9
+	cpfsgt	opt_max							; max value > 9 ?
+	bsf		hide_digit2						; NO  - do not show digit 2
+
+	output_256								; print option value
+
+	movf	opt_unit+0,W					; is there a unit to append?
+	iorwf	opt_unit+1,W					; ...
+	bz		option_draw_uint8_common		; NO  - continue with common part
+	movff	opt_unit+0,FSR1L				; YES - pointer to multi-lingual unit text
+	movff	opt_unit+1,FSR1H				;     - ...
+	call	strcat_text_FSR					;     - append unit text to buffer
+	;bra	option_draw_uint8_common		;     - continue with common part
+
+
+;-----------------------------------------------------------------------------
+; Helper Function - common Part for INT
+;
+option_draw_uint8_common:
+	movf	opt_default,W					; get default value
+	cpfseq	lo								; compare with current value, equal?
+	bra		option_draw_uint8_common_1		; NO  - not default, add *
+	return									; YES - default, done
+option_draw_uint8_common_1:
+	PUTC	"*"								; print "*"
+	return									; done
+
+
+;-----------------------------------------------------------------------------
+; Helper Function - draw an ENUM (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_FSR					; 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
+
+
+;=============================================================================
+options2	CODE
+;=============================================================================
+
+
+;-----------------------------------------------------------------------------
+; Check and Resolve some Interdependencies among Option Values
+;
+option_crosschecks:
+	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
+
+	rcall	option_cleanup_GF				; check and correct GFlow <= GFhigh
+
  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
-
+	rcall	option_cleanup_gauge			; check and correct gauge mode
+ ENDIF	; _gauge_mode
 
  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
+	rcall	option_cleanup_oCCRMode			; check and correct CCR / pSCR mode
  ENDIF	; _ccr_pscr
 
+ IFDEF _helium
+	rcall	option_cleanup_sum_O2_He		; check and correct O2% + He% <= 100  +++
+ ENDIF	; _helium
 
+	return									; done
+
+
+;-----------------------------------------------------------------------------
+; Check and correct GFs so that GF_high >= GF_low
+;
 option_cleanup_GF:
 	; cleanup normal GF
 	movff	opt_GF_high,WREG				; copy normal GF high to WREG
@@ -654,7 +924,7 @@
 	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
+	bsf		option_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
@@ -668,93 +938,86 @@
 	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
+	bsf		option_changed					; flag that EEPROM needs to be updated
 option_cleanup_GF_4:
 	return									; done
 
-
-;=============================================================================
-; Strcat option into FSR2 buffer
+;-----------------------------------------------------------------------------
+; Check and correct Dive Mode if Gauge Mode is not allowed
 ;
-	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 "*"
+ 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		option_changed					;     - flag that EEPROM needs to be updated
+option_cleanup_gauge_1:
 	return									; done
-
-option_draw_unit:
-	movff	opt_unit+0,FSR1L
-	movff	opt_unit+1,FSR1H
-	goto	strcat_text
+ ENDIF	; _gauge_mode
 
 
-;---- 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
+;-----------------------------------------------------------------------------
+; Check and correct AutoSP and external Sensor Settings dependent on Modes
+;
+ 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		option_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	ext_input_s8_ana				; S8/analog interface available?
+	return									; YES - setting 'sensor' allowed
+	btfsc	ext_input_optical				; does hosting OSTC have an optical interface?
+	return									; YES - setting 'sensor' allowed
+ ENDIF	; _external_sensor
+	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		option_changed					;                  - flag that EEPROM needs to be updated
+	return									;                  - done
+ ENDIF	; _ccr_pscr
+
+
+;-----------------------------------------------------------------------------
+; Check and correct that O2% + He% <= 100%
+;
+ IFDEF _helium
+option_cleanup_sum_O2_He:
+	lfsr	FSR0,opt_gas_He_ratio-1		; load (base address of He% array - 1) because of PREINC
+	movlw	2*NUM_GAS					; load loop counter
+	movwf	lo							; ...
+option_cleanup_sum_loop:
+	movff	PREINC1,up					; get He ratio
+	movlw	-2*NUM_GAS					; address O2 ratio
+	movff	PLUSW0,hi					; get O2 ratio
+	movlw	.100						; load WREG with 100%
+	bsf		STATUS,C					; set carry = clear borrow
+	subfwb	hi,W						; subtract O2% from WREG
+	subfwb	up,W						; subtract He% from WREG
+	btfsc	STATUS,C					; result negative?
+	bra		option_cleanup_sum_loop_1	; NO  - sum valid
+	clrf	INDF1						; YES - heal by setting He% to zero
+	bsf		option_changed				; flag that EEPROM needs to be updated
+option_cleanup_sum_loop_1:
+	decfsz	lo							; decrement loop counter, all done?
+	bra		option_cleanup_sum_loop		; NO  - loop
+	return								; YES - done
+ ENDIF	; _helium
+
 
 ;-----------------------------------------------------------------------------