;============================================================================
; sotware source for TELEFLIC
; by Robert LACOSTE
;
; version 1.02
;
; 68705P3 code, to be assembled with AS6805
;============================================================================

;----------------------------------------------------------------------------
; Constants declarations
;----------------------------------------------------------------------------

VAL_TIM	=	0d98		; timer load value (irq every 12,5ms-80Hz)
BLVAL	=	0d20		; blinking speed (20 = 1/2 sec)
KDEBOUN	=	0d2		; constant for push-button debouncing

;----------------------------------------------------------------------------
; Page 0 header for AS6805
;----------------------------------------------------------------------------

	.area	DIRECT
	.setdp	0,DIRECT

;----------------------------------------------------------------------------
; 68705 Registers definition (0x00-0x0F)
;----------------------------------------------------------------------------

DATAA	=	0x00
DATAB	=	0x01
DATAC	=	0x02
DDRA	=	0x04
DDRB	=	0x05
DDRC	=	0x06
TDR	=	0x08
TCR	=	0x09
PCR	=	0x0B

;----------------------------------------------------------------------------
; RAM (0x10-0x7F, stack from 0x7F downto 0x61 included)
;----------------------------------------------------------------------------

tmp1	= 	0x10		; temporary data
tmp2	= 	0x11		; temporary data

val	=	0x12		; value to be displayed (0 to 199)
l_on	=	0x13		; led "on" to be put on if not 0
l_mst	=	0x14		; led "master" to be put on if not 0

blink	=	0x15		; counter for display blinking
blstat	=	0x16		; state of display blinking (0 or 0xff)
pdispl	=	0x17		; part of display last time showed (0 or ff)

b_plus	=	0x18		; state of push-buttons
b_moins	=	0x19		; put to 0xff if new button pressed
b_mast	=	0x1a		; put back to 0 by user

c_bpl	=	0x1b		; counters for push-button filtering
c_bmo	=	0x1c
c_bma	=	0x1d

appth	=	0x1e		; application timer (decremented every sec)
apptl	=	0x1f		; (16 bit value)
apptc	=	0x20		; 80/80 sec counter (80 downto 0)

keyd	=	0x21		; key detected (0-199 for user,
				; 0xff for no key, 0xee for master
keydc	=	0x22		; 20/80 sec counter (20 downto 0)

state	=	0x23		; current state number (for debug only)

; Variables used by interrupt routines
sv_tmp1	=	0x24		; save tmp1
sv_tmp2	=	0x25		; save tmp2

; NEED TO END BEFORE 0x7F - 32 (STACK) = 5F !!!

;----------------------------------------------------------------------------
; EPROM code (0x100-0x783)
;----------------------------------------------------------------------------

	.area	PGM (ABS)
	.org	0x100

;***********************************************
; System initialisation
;***********************************************

reset:	
	; I/O ports configuration

	lda 	#0b10000000		; port A : only B7 as output
	sta 	*DDRA
	lda 	#0b11111111		; port B : every pin as output
	sta 	*DDRB
	lda 	#0b11110111		; port V : C0, C1, C2 as output
	sta 	*DDRC

	; ram initialisation
	lda 	#0
	sta	*val
	sta	*l_on
	sta	*l_mst
	sta	*blstat
	sta	*pdispl
	sta	*b_plus
	sta	*b_moins
	sta	*b_mast
	sta	*c_bpl
	sta	*c_bmo
	sta	*c_bma
	sta	*state

	lda	#BLVAL
	sta	*blink

	lda	#0d80
	sta	*apptc

	lda	#0d20
	sta	*keydc

	lda	#0xff
	sta	*keyd

	; Timer and interrupts configuration
	lda 	#VAL_TIM		; initial timer load
	sta	*TDR
	bclr	#7,*TCR			; timer interrupt clear
	bclr	#6,*TCR			; timer interrupt enable
	cli				; enable processor interrupts

	; Go to main program
	jmp	main

;***********************************************
; Main program
;***********************************************

main:	
	jmp	S_idle			; Begin by state Idle

;***********************************************
; Main state machine
;
; - States are labeled S_xxxx
; - On each state, possible transitions are processed
; - If a transition in valid, action(s) are executed (P_xxx)
;   and a new state is reached
;
; About interrupts :
; A lot of code in the state machine can't be preempted
; (test and set in a few instructions, etc). In order to
; avoid potential slide effects, interrupts are only
; processed at the beginning of each state loop.
;***********************************************

;================= STATE: idle mode

S_idle:
	cli			; enable interrupts just here
	sei
	lda	#1		; save state number (for debug)
	sta	*state

	jsr	P_off		; Put load off (just in case...)

	tst	*b_mast		; TRANSITION: 	"master" button pressed
	beq	1$
	lda	#0
	sta	*b_mast
	jsr	P_cmst		; ACTION:	create master key
	jmp	S_idle		; NEW STATE:	idle mode

1$:	lda	*keyd		; TRANSITION:	not empty user key detected
	cmp	#0d199
	bhi	2$
	lda	*keyd
	beq	2$
	jsr	P_on		; ACTION:	put load on
	jmp	S_on		; NEW STATE:	on mode

2$:	lda	*keyd		; TRANSITION:	master key detected
	cmp	#0xee
	bne	100$
	jsr	P_mst		; ACTION:	master mode on
	jmp	S_mast		; NEW STATE:	master present

100$:	jmp	S_idle		; no other transition

;================= STATE: on mode

S_on:
	cli			; enable interrupts just here
	sei
	lda	#2		; save state number (for debug)
	sta	*state

	tst	*b_mast		; TRANSITION: 	"master" button pressed
	beq	1$
	lda	#0
	sta	*b_mast
	jsr	P_off		; ACTION:	put load off
	jsr	P_cmst		; ACTION:	create master key
	jmp	S_idle		; NEW STATE:	idle mode

1$:	lda	*keyd		; TRANSITION:	no non-empty user key
	cmp	#0
	beq	21$
	cmp	#0xee
	beq	21$
	cmp	#0xff
	beq	21$
	bra	2$
21$:	jsr	P_ontp		; ACTION:	enter on tempo state
	jmp	S_ontp		; NEW STATE:	on with tempo

2$:	jsr	testt		; TRANSITION:	application timer exhausted
	bne	100$
	jsr	P_dkey		; ACTION:	decrement key by 1 tick
	jmp	S_on		; NEW STATE:	on mode

100$:	jmp	S_on		; no other transition

;================= STATE: on with tempo

S_ontp:
	cli			; enable interrupts just here
	sei
	lda	#4		; save state number (for debug)
	sta	*state

	lda	*keyd		; TRANSITION: 	master key detected
	cmp	#0xee
	bne	1$
	jsr	P_mst		; ACTION:	master mode on
	jmp	S_mast		; NEW STATE:	master present

1$:	lda	*keyd		; TRANSITION:	not empty user key detected
	cmp	#0d199
	bhi	2$
	lda	*keyd
	beq	2$
	jsr	P_on		; ACTION:	put load on
	jmp	S_on		; NEW STATE:	on mode

2$:	jsr	testt		; TRANSITION:	application timer exhausted
	bne	100$
	jsr	P_off		; ACTION:	put load off
	jmp	S_idle		; NEW STATE:	idle mode

100$:	jmp	S_ontp		; no other transition

;================= STATE: master present

S_mast:
	cli			; enable interrupts just here
	sei
	lda	#3		; save state number (for debug)
	sta	*state

	tst	*b_moins	; TRANSITION: 	"minus" button pressed
	beq	1$
	lda	#0
	sta	*b_moins
	jsr	P_crus		; ACTION:	create full user key
	jsr	P_cfgu		; ACTION:	enter config user mode
	jmp	S_cfgu		; NEW STATE:	config user mode

1$:	lda	*keyd		; TRANSITION:	no more master key
	cmp	#0xee
	beq	100$
	jsr	P_mstp		; ACTION:	enter master tempo state
	jmp	S_mttp		; NEW STATE:	master tempo

100$:	jmp	S_mast		; no other transition

;================= STATE: master tempo

S_mttp:
	cli			; enable interrupts just here
	sei
	lda	#5		; save state number (for debug)
	sta	*state

	jsr	testt		; TRANSITION:	application timer exhausted
	bne	1$
	jsr	P_msof		; ACTION:	master mode off
	jmp	S_idle		; NEW STATE:	idle mode

1$:	lda	*keyd		; TRANSITION: 	master key detected
	cmp	#0xee
	bne	2$
	jsr	P_mst		; ACTION:	master mode on
	jmp	S_mast		; NEW STATE:	master present

2$:	lda	*keyd		; TRANSITION:	user key detected
	cmp	#0xee
	beq	100$
	cmp	#0xff
	beq	100$
	jsr	P_cfgu		; ACTION:	enter config user mode
	jmp	S_cfgu		; NEW STATE:	config user key

100$:	jmp	S_mttp		; no other transition

;================= STATE: config user key

S_cfgu:
	cli			; enable interrupts just here
	sei
	lda	#6		; save state number (for debug)
	sta	*state

	lda	*keyd		; TRANSITION:	no user key detected
	cmp	#0xee
	beq	11$
	cmp	#0xff
	beq	11$
	bra	1$
11$:	jsr	P_mstp		; ACTION:	enter master tempo state
	jmp	S_mttp		; NEW STATE:	master tempo

1$:	jsr	testt		; TRANSITION:	application timer exhausted
	bne	2$
	jsr	P_msof		; ACTION:	master mode off
	jmp	S_idle		; NEW STATE:	idle mode

2$:	tst	*b_moins	; TRANSITION: 	"minus" button pressed
	beq	3$
	lda	#0
	sta	*b_moins
	jsr	P_minu		; ACTION:	increment cfg key
	jsr	P_cfgu		; ACTION:	enter config user mode
	jmp	S_cfgu		; NEW STATE:	config user mode

3$:	tst	*b_plus		; TRANSITION: 	"plus" button pressed
	beq	100$
	lda	#0
	sta	*b_plus
	jsr	P_plus		; ACTION:	decrement cfg key
	jsr	P_cfgu		; ACTION:	enter config user mode
	jmp	S_cfgu		; NEW STATE:	config user mode

100$:	jmp	S_cfgu		; no other transition

;================= ACTION : create master key

P_cmst:	lda	#0xee		; write master key code to eeprom
	jsr	wrkey
	rts

;================= ACTION : put load on

P_on:	bset	#7,*DATAA	; put relay on
	lda	#1		; put green led on
	sta	*l_on
	jsr	ldtick		; load application timer from jumpers
	rts

;================= ACTION : decrement key by 1 tick

P_dkey:	jsr	ldtick		; reload application timer from jumpers
	lda	*keyd		; decrement key value
	beq	2$
	deca
	cmp	#0d199		; should be 0<=x<199
	bls	1$
	lda	#0d199
1$:	sta	*keyd
	jsr	wrkey		; and store new value in eeprom
2$:	rts

;================= ACTION : enter on tempo state

P_ontp:	lda	#<10		; load application timer by 10 seconds
	sta 	*apptl
	lda	#>10
	sta 	*appth
	rts

;================= ACTION : put load off

P_off:	bclr	#7,*DATAA	; put relay off
	lda	#0		; put green led off
	sta	*l_on
	rts

;================= ACTION : master mode on

P_mst:	bset	#7,*DATAA	; put relay on
	lda	#1		; put green led on
	sta	*l_on
	sta	*l_mst		; put yellow led on
	rts

;================= ACTION : create full user key

P_crus:	lda	#0d199		; write 0d199 to eeprom
	jsr	wrkey
	rts

;================= ACTION : enter master tempo state

P_mstp:	lda	#<10		; load application timer by 10 seconds
	sta 	*apptl
	lda	#>10
	sta 	*appth
	rts

;================= ACTION : enter config user mode

P_cfgu:	lda	#<5		; load application timer by 5 seconds
	sta 	*apptl
	lda	#>5
	sta 	*appth
	rts

;================= ACTION : master mode off

P_msof:	bclr	#7,*DATAA	; put relay off
	lda	#0		; put green led off
	sta	*l_on
	sta	*l_mst		; put yellow led off
	rts

;================= ACTION : increment cfg key

P_plus:
	lda	*keyd		; increment key value by 20
	add	#0d20
	cmp	#0d199		; should be 0<=x<199
	bls	1$
	lda	#0d199
1$:	sta	*keyd
	jsr	wrkey		; and store new value in eeprom
	rts

;================= ACTION : decrement cfg key

P_minu:
	lda	*keyd		; decrement key value by 20
	sub	#0d20
	bpl	1$
	cmp	#0d199
	bls	1$		; test if 0<=x<=199
	lda	#0
1$:	sta	*keyd
	jsr	wrkey		; and store new value in eeprom
	rts

;***********************************************
; EEPROM read
;
; EEPROM content : 
;   - only first word is used (16 bits)
;   - second byte is first byte complementary for correctly
;     initialised keys
;   - First byte is 0 (key exausted), 1 to 199 user key loaded,
;     or 0xff (master key)
;
; Warning : interrupts should be disabled before executing this routine
;***********************************************

rdkey:	bset	#0,*DATAC	; put CS on
	sec
	jsr	trbit		; send read header (110) and address (000000)
	lda	#0b10000000
	jsr	trbyte	
	jsr	rdbyte		; read a word (two bytes)
	sta	*tmp1
	jsr	rdbyte
	sta	*tmp2	
	bclr	#2,*DATAC	; put DI off
	bclr	#0,*DATAC	; put CS off
	lda	*tmp2		; verify if second byte = complement of first
	coma
	cmp	*tmp1
	bne	1$ 		; if not, return 0xff (no key)
	cmp	#0d199		; if <= 199, it's ok
	bls	10$
	cmp	#0xee		; if 0xee (master key), it's ok
	beq	10$
1$:	lda	#0xff		; else return 0xff (no valid key)
10$: 	rts

; Transmit one bit to EEPROM (stored in C)
trbit:	bcc	1$		; put DI line to 1 or 0
	bset	#2,*DATAC
	bra	2$
1$:	bclr	#2,*DATAC
2$:	bset	#1,*DATAC	; toggle SK line
	bclr	#1,*DATAC
	rts

; transmit one byte (stored in A), MSB first
trbyte:	ldx	#8
1$:	rola
	jsr	trbit
	decx
	bne	1$
	rts

; read one byte (result in A)
rdbyte:	ldx	#8
1$:	bset	#1,*DATAC	; toggle SK line
	brclr	#3,*DATAC,2$	; read bit on DO
2$:	rola			; save bit in A (msb received first)
	bclr	#1,*DATAC	; release SK line
	decx
	bne	1$		; loop for 8 bits
	rts

;***********************************************
; EEPROM write
; (data to be writen in A)
; This function take 25ms to be executed
;***********************************************

wrkey:	sta	*tmp1		; store value to be send

	; switch device to write enable mode
	bset	#0,*DATAC	; put CS on
	sec
	jsr	trbit		; send command header (100) & address (110000)
	lda	#0b00110000
	jsr	trbyte	
	bclr	#2,*DATAC	; put DI off
	bclr	#0,*DATAC	; put CS off
	nop
	nop
	nop

	; send write command
	bset	#0,*DATAC	; put CS on
	sec
	jsr	trbit		; send write header (101) & address (000000)
	lda	#0b01000000
	jsr	trbyte	
	lda	*tmp1		; and then data (A and complement of A)
	jsr	trbyte
	lda	*tmp1
	coma
	jsr	trbyte
	bclr	#2,*DATAC	; put DI off
	bclr	#0,*DATAC	; put CS off
	nop
	nop
	nop

	; busy flag detection
	bset	#0,*DATAC	; put CS on
1$:	brclr	#3,*DATAC,1$	; wait DO to be on
	bclr	#0,*DATAC	; put CS off

	rts

;***********************************************
; Push-buttons handling
;
; needs to be executed every 1/40 second.
; read push-button states, filter them, and
; if a new button is pushed, set to one the
; associated variable (b_plus,b_moins,b_mast).
; The reset of these variables have to be done manualy
;***********************************************

pshb:
	brclr	#0,*DATAA,1$		; check if "less" pressed
	lda	#0
	sta	*c_bmo			; if not, reser counter
	bra	20$
1$:	lda	*c_bmo			; check if counter=0xff
	cmp	#0xff
	beq	20$			; if yes, wait putton to be released
	inc	*c_bmo			; else increment counter
	lda	*c_bmo
	cmp	#KDEBOUN		; and compare to limit
	blo	20$
	lda	#0xff			; if greater, button pushed
	sta	*b_moins
	sta	*c_bmo

20$:	brclr	#1,*DATAA,2$		; check if "plus" pressed
	lda	#0
	sta	*c_bpl			; if not, reser counter
	bra	30$
2$:	lda	*c_bpl			; check if counter=0xff
	cmp	#0xff
	beq	30$			; if yes, wait putton to be released
	inc	*c_bpl			; else increment counter
	lda	*c_bpl
	cmp	#KDEBOUN		; and compare to limit
	blo	30$
	lda	#0xff			; if greater, button pushed
	sta	*b_plus
	sta	*c_bpl

30$:	brclr	#2,*DATAA,3$		; check if "create master" pressed
	lda	#0
	sta	*c_bma			; if not, reser counter
	bra	40$
3$:	lda	*c_bma			; check if counter=0xff
	cmp	#0xff
	beq	40$			; if yes, wait putton to be released
	inc	*c_bma			; else increment counter
	lda	*c_bma
	cmp	#KDEBOUN		; and compare to limit
	blo	40$
	lda	#0xff			; if greater, button pushed
	sta	*b_mast
	sta	*c_bma

40$:	rts

;***********************************************
; Leds ramp handling
;
; needs to be executed every 1/80 second (for refresh speed 40Hz).
; read ram data (val, l_on, l_mst) 
; and do the display multiplexing.
;***********************************************

dlpl:	
	com	*pdispl			; change part of display to show

	dec	*blink			; check blinking counter
	bne	1$
	lda	#BLVAL
	sta	*blink
	com	blstat			; and change blinking state if needed

1$: 	lda	*val			; check if val >20
	cmp	#20
	bhs	dlpl1			; if yes, continue
	brset	#6,*DATAA,dlpl1		; else test if jumper "/10" active
	tst	blstat			; if yes test blinking state
	beq	2$
	lda	#0			; if state off, display off
	bra	dlpl1
2$:	lda	*val			; else get value to be displayed
	add	*val			; and multiply by 10
	add	*val
	add	*val
	add	*val
	add	*val
	add	*val
	add	*val
	add	*val
	add	*val

dlpl1:	tst	*pdispl			; check part of display to show
	beq	dlpl2
			
	cmp	#0d101			; low part of ramp
	blo	1$			; change value to ramp state
	lda	#0b00000001
	bra	dlpl4
1$:	cmp	#0d81		
	blo	2$	
	lda	#0b10000001
	bra	dlpl4
2$:	cmp	#0d61		
	blo	3$	
	lda	#0b11000001
	bra	dlpl4
3$:	cmp	#0d41		
	blo	4$	
	lda	#0b11100001
	bra	dlpl4
4$:	cmp	#0d21		
	blo	5$	
	lda	#0b11110001
	bra	dlpl4
5$:	cmp	#0d1		
	blo	6$	
	lda	#0b11111001
	bra	dlpl4
6$:	lda	#0b11111101
	bra	dlpl4

dlpl2: 	cmp	#0d181			; high part of ramp and leds
	blo	1$	
	lda	#0b00001110
	bra	dlpl3
1$:	cmp	#0d161		
	blo	2$	
	lda	#0b00011110
	bra	dlpl3
2$:	cmp	#0d141		
	blo	3$	
	lda	#0b00111110
	bra	dlpl3
3$:	cmp	#0d121		
	blo	4$	
	lda	#0b01111110
	bra	dlpl3
4$:	lda	#0b11111110

dlpl3 :					; add leds if needed
	tst	*l_on
	beq	1$
	and	#0b11110111
1$:	tst	*l_mst
	beq	dlpl4
	and	#0b11111011

dlpl4:	sta	*DATAB			; activate display
	rts

;***********************************************
; Test if application timer is exhausted
; (test "beq" true on exit if exhausted)
;***********************************************

testt:	tst	*appth
	bne	10$
	tst	*apptl
10$:	rts

;***********************************************
; Load application timer with duration in second
; of a "tick", depending on jumpers JP1-JP3
; (1/20 of step duration)
;***********************************************

ldtick:	lda	*DATAA			; get jumpers state
	lsra
	lsra
	lsra
	and	#0b00000111
	cmp	#0b000			; 4H
	bne	1$
	lda	#<0d720
	sta	*apptl
	lda	#>0d720
	sta	*appth
	bra	20$
1$:	cmp	#0b100			; 2H
	bne	2$
	lda	#<0d360
	sta	*apptl
	lda	#>0d360
	sta	*appth
	bra	20$
2$:	cmp	#0b010			; 1H
	bne	3$
	lda	#<0d180
	sta	*apptl
	lda	#>0d180
	sta	*appth
	bra	20$
3$:	cmp	#0b110			; 1/2H
	bne	4$
	lda	#<0d90
	sta	*apptl
	lda	#>0d90
	sta	*appth
	bra	20$
4$:	cmp	#0b001			; 1/4H
	bne	5$
	lda	#<0d45
	sta	*apptl
	lda	#>0d45
	sta	*appth
	bra	20$
5$:	cmp	#0b101			; 10'
	bne	6$
	lda	#<0d30
	sta	*apptl
	lda	#>0d30
	sta	*appth
	bra	20$
6$:	cmp	#0b011			; 5'
	bne	7$
	lda	#<0d15
	sta	*apptl
	lda	#>0d15
	sta	*appth
	bra	20$
7$:	lda	#<0d3			; 1'
	sta	*apptl
	lda	#>0d3
	sta	*appth

20$: 	rts

;***********************************************
; Timer interrupt (executed 80 times each second)
;***********************************************

it_tim:	
	lda 	#VAL_TIM		; reload timer
	sta	*TDR
	bclr	#7,*TCR			; clear timer interrupt request
	lda	*tmp1			; save tmp1
	sta	*sv_tmp1
	lda	*tmp2			; and tmp2
	sta	*sv_tmp2

; executed every 1/80 second
	jsr	dlpl			; refresh display

	jsr	pshb			; read push-buttons

	dec	*apptc			; decrement 80/80 s counter
	bne	it_nsc

; executed every second
	lda	#0d80
	sta	*apptc			; reload 80/80s counter

	tst	*appth			; if application timer not nul
	bne	10$
	tst	*apptl
	beq	it_nsc
10$:	lda	*apptl			; ... decrement application timer
	sub	#1
	sta	*apptl
	lda	*appth
	sbc	#0
	sta	*appth

it_nsc:
; executed every 1/80 second
	dec	*keydc			; decrement 20/80 s counter
	bne	it_nky

; executed every 20/80 second
	lda	#0d20
	sta	*keydc			; reload 20/80s counter

	jsr	rdkey			; read key (if present)
	sta	keyd			; save read value
	cmp	#0xff			; test if key present
	bne	1$
	lda	#0			; if not, no led to light
1$:	sta	val			; else display key value

it_nky:
; executed every 1/80 second

	brclr	#7,*TCR,2$		; test if timer overrun
	lda	#0d01			; if yes, fatal error #1
	jmp	error
2$:
	lda	*sv_tmp1		; restore tmp1
	sta	*tmp1
	lda	*sv_tmp2		; and tmp2
	sta	*tmp2
	rti				; return to main program

;***********************************************
; Error handling (A value displayed on 6 leds)
; Should never be executed ...
;***********************************************

error:
	sei				; stop interrupts, if enabled
	sta	tmp1			; save error value
berror:	lda	#0b11110010		; two leds on
	sta	*DATAB
	jsr	tmperr			; wait
	lda	tmp1			; plot error value
	coma
	lsla
	lsla
	ora	#0b00000001
	sta	*DATAB
	jsr 	tmperr
	jmp	berror			; never exit

tmperr:	lda	#0d80			; active temporisation
	sta	*tmp2
tmper1:	lda	#0xff
tmper2:	deca
	bne	tmper2
	dec	*tmp2
	bne	tmper1
	rts

; NEED TO END BEFORE 0x783 !!!

;----------------------------------------------------------------------------
; MASK OPTION REGISTER (0x784)
;----------------------------------------------------------------------------

	.org	0x784

	;b7=0 (crystal)
	;b6=0 (timer programmed by software, next bits are initial values)
	;b5=0 (interner timer source)
	;b4=0 (no use of timer pin)
	;b3=0 (not used)
	;b2/b1/b0=111 (timer prescaler divide by 128)

	.db	0b00000111

;----------------------------------------------------------------------------
; VECTORS (0x7F8-0x7FF)
;----------------------------------------------------------------------------

	.org	0x7f8

; Timer interrupt vector
	.dw	it_tim

; External interrupt vector
	.dw	reset

; SWI vector
	.dw 	reset

; Reset vector
	.dw	reset

;----------------------------------------------------------------------------
; END-OF-FILE
;----------------------------------------------------------------------------

