;***************************************************************************
;
; function assembles source by	: Hugo Vos
;				: 15-4-98
;
; E-mail			: hugo@hvos.myweb.nl
;
;
; Functions:	HEX2DEC      , converts a HEX vallue into a DEC vallue ( $0F = $15 )
;		DEC2HEX      , converts a DEC vallue into a HEX vallue ( $15 = $0F )
;		modDECval    , inc or dec a DEC vallue between specified min. and max. vallue
;		modHEXval    , inc or dec a HEX vallue between specified min. and max. vallue
;		Beep         , creates a tone on the speaker
;		Sendtime     , Send current time/date to RS-232 port.
;		disp_RTCtime , displays time on display: Ax disp pos, Bx hour
;		createArray  , Create vallid time's array in SRAM
;		dispDECval   , display a DEC number on the display
;		SendDECval   , Send DEC value define in AX to the UART
;		Send_chanstat, Send channel number and statas on the RS-232 port
;
;***************************************************************************
;
; Routine convert a HEX vallue to a DEC vallue
;
; Parameters : Ax = HEX vallue
; Return     : Ax = DEC vallue
;
;***************************************************************************

HEX2DEC:

	push	Bx
	push	Cx

	mov	Bx, Ax				; Load Bx with HEX vallue
	ldi	Ax, $00				

HEXdec:
	cpi	Bx, $0A
	brlt	end10inc			; end loop if Bx < 10 dec
	subi	Ax, $F0				; increase Ax with 10 dec
	subi	Bx, $0A
	rjmp	HEXdec

end10inc:
	add	Ax, Bx
	pop	Cx
	pop	Bx

	ret

;***************************************************************************
;
; Routine to converte a DEC vallue to a HEX vallue
;
; Parameters : Ax = DEC vallue
; Return     : Ax = HEX vallue
;
;***************************************************************************

DEC2HEX:

	push	Bx
	push	Cx

	push	Ax				; save Ax onto stack
	mov	Bx, Ax				; Load Bx with DEC vallue
	swap	Bx
	andi	Bx, $0F				; Bx contains DEC 10's vallue
	ldi	Cx, $00
	ldi	Ax, $0A

inclus:
	cpi	Bx, $00				 
	breq	endinclus
	add	Cx, Ax
	dec	Bx
	rjmp	inclus

endinclus:	
	pop	Ax				; load Ax with org vallue
	andi	Ax, $0F				; Remove 10's from DEC  vallue
	add	Ax, Cx				; add them to Bx
						; Ax contains HEX vallue 
	pop	Cx
	pop	Bx
	
	ret

;***************************************************************************
;
; modify DEC vallue specified :
;	  Ax = DEC vallue
;	  Bx = min. DEC vallue
;	  Cx = Max. vallue + 1
;
; Return: Ax, new DEC vallue.
;	  Bx, last pressed key vallue 
;
;***************************************************************************

moddecval:

	push	Ax			; Save DEC vallue

Read_key:

	in	Ax, PinB		; Read input key's
	andi	Ax, $0F
	
	cpi	Ax, return_key		; Check if return key is pressed
	breq	end_moddecval		

	cpi	Ax, select_key		; check if select key is pressed
	breq	end_moddecval

	cpi	Ax, plus_key		; Check if "+" key is pressed
	breq	inc_DECVAL

	cpi	Ax, min_key		; Check if "-" key is pressed
	breq	dec_DECVAL	

	rjmp	Read_key		; read key's again if no key is pressed

; **********************************
; Start of increase DEC-val routine
; **********************************

inc_DECVAL:

	rcall	Beep
	pop	Ax			; Get Vallue
	inc	Ax			; Increase vallue by 1

	push	Ax			; Save DECval on stack
	andi	Ax, $0f			
	cpi	Ax, $0a			; check of "0A" = 10 in low nibble Ax
	breq	add_10h			; if so, then jump to add_10h
	pop	Ax			; if not, pull Decval from stack
	rjmp	stop_moddecvalinc	; Jump to end of subroutine

add_10h:
	pop	Ax			; pull DECval from stack
	subi	Ax, $F0			; Inc Ax with 10
	andi	Ax, $F0			; make DECval low nibble "0"

stop_moddecvalinc:

	cp	Ax, Cx			; check DECval for max. vallue specified in Cx register
	brne	end_maxcheck		; Jump is not equel to max vallue
	mov	Ax, Bx			; load DECval with min. vallue specified in Bx register.

end_maxcheck:
	ldi	Bx, $00			; load Bx with "00" to specify + or - key function
	rjmp	end_DECsub

; **********************************
; Start of decrease DEC-val routine
; **********************************

dec_DECVAL:
	rcall	Beep
	pop	Ax			; Get Vallue
	cp	Bx, Ax			; check if Ax if Min vallue
	brne	dec_val			; is not then decrease AX, or else
	mov	Ax, Cx			; load Ax with Max. val - 1
	dec	Ax			; decrease Ax by 1
	mov	Cx, Ax			; load Cx with new valleu
	andi	Cx, $0F
	cpi	Cx, $0F			; check for low nibble is "F"
	brne	end_mincheck		; if low nibble is "F" then
	subi	Ax, $06			; subtrak 6 from Ax to get "9" in low nibble
	rjmp	end_mincheck

dec_val:
	dec	Ax			; decrease Ax with 1
	push	Ax
	andi	Ax, $0F
	cpi	Ax, $0F
	pop	Ax
	brne	end_mincheck
	subi	Ax, $06			; Decrease Ax with 6 to make Ax low nibbel "9"

end_mincheck:
	ldi	Bx, $00			; load Bx with "00" to specify + or - key function
	rjmp	end_DECsub

end_moddecval:
	rcall	Beep
	mov	Bx, Ax			; save last key vallue into Bx
	pop	Ax			; pull DECval from stack
	
end_DECsub:

	ret				; return from subroutine

;***************************************************************************
;
; modify HEX vallue specified :
;	  Ax = DEC vallue
;	  Bx = min. HEX vallue
;	  Cx = Max. HEX vallue + 1
;
; Return: Ax, new HEX vallue.
;	  Bx, last pressed key vallue 
;
;***************************************************************************

modHEXval:

	push	Ax			; Save DEC vallue

hex_read_key:

	in	Ax, PinB		; Read input key's
	andi	Ax, $0F
	
	cpi	Ax, return_key		; Check if return key is pressed
	breq	end_modhexval		

	cpi	Ax, select_key		; check if select key is pressed
	breq	end_modhexval

	cpi	Ax, plus_key		; Check if "+" key is pressed
	breq	inc_HEXVAL

	cpi	Ax, min_key		; Check if "-" key is pressed
	breq	dec_HEXVAL	

	rjmp	hex_Read_key		; read key's again if no key is pressed

; **********************************
; Start of increase HEX-val routine
; **********************************

inc_HEXVAL:
	rcall	Beep
	pop	Ax			; Get Vallue
	inc	Ax			; Increase vallue by 1
		
	cp	Ax, Cx			; check HEXval for max. vallue specified in Cx register
	brne	end_maxHEXcheck		; Jump is not equel to max vallue
	mov	Ax, Bx			; load HEXval with min. vallue specified in Bx register.

end_maxHEXcheck:
	ldi	Bx, $00			; load Bx with "00" to specify + or - key function
	rjmp	end_HEXsub

; **********************************
; Start of decrease HEX-val routine
; **********************************

dec_HEXVAL:
	rcall	Beep
	pop	Ax			; Get Vallue
	cp	Bx, Ax			; check if Ax if Min vallue
	brne	dec_HEX			; is not then decrease AX, or else
	mov	Ax, Cx			; load Ax with Max. val - 1
	dec	Ax			; decrease Ax by 1
	rjmp	end_minHEXcheck

dec_HEX:
	dec	Ax			; decrease Ax with 1

end_minHEXcheck:
	ldi	Bx, $00			; load Bx with "00" to specify + or - key function
	rjmp	end_DECsub

end_modHEXval:

	rcall	Beep
	mov	Bx, Ax			; save last key vallue into Bx
	pop	Ax			; pull DECval from stack
	
end_HEXsub:

	ret				; return from subroutine

;***************************************************************************
;
; Creates a tone on the speaker
;
;***************************************************************************

Beep:
	push	Ax
	in	Ax, TIMSK
	ori	Ax, 0b00000010		; Enable Timer 0 overflow INT
	out	TIMSK, Ax
	rcall	delay_5ms		; Enable 5mS tone output onto speaker
	in	Ax, TIMSK
	andi	Ax, 0b11111101		; Disable Timer 0 overflow INT
	out	TIMSK, Ax
	pop	Ax

	cbi	PORTC, 2

	ret

;***************************************************************************
;
; converts vallue to ASC code and send it to the RS-232 port
;
;***************************************************************************

SendTime:

	push	Ax			; Save namen registers on stack
	push	Bx
	push	Cx
	push	Z_low
	push	Z_high

;********* START OF SENDEN THE TIME ON THE RS-232 PORT **********

	
	ldi	Cx, $03			; Load Cx as cycle counter
	ldi	Bx, $04			; load Bx with RTC clock start register value
	
Start_timesend:
	
	ldi	Ax, PCF8583		; load I2C adres into Ax
					; Bx is loaded with Reg. number
	rcall	I2C_regread		; Load register vallue from RTC into Ax register	

	push	Ax			; Save read value on stack
	andi	Ax, $F0			; clear low nibble
	swap	Ax			; and move high nibble to low nibble
	subi	Ax, $D0			; and convert DEC val into ASCII val.
	rcall	sendCHR			; an send it to RS-232 port

	pop	Ax			; Reload Ax with read value
	andi	Ax, $0F			; clear high nibble
	subi	Ax, $D0			; and convert it into ASCII val
	rcall	sendCHR			; and send it to RS-232 port

	dec	Cx			; decrease cycle counter and
	cpi	Cx, $00			; check for end of cycle
	breq	end_timesend		; if not, jump to begin of loop
	
	ldi	Ax, $3A			; send ":" CHR to RS-232 port
	rcall	sendCHR	
	dec	Bx			; Decrease reg. number by one
	rjmp	Start_timesend
	
end_timesend:	
	ldi	Ax, $20			; load Ax with " " CHR	
	rcall	sendCHR


;********* START SENDING CURRENT DAY BY NAME TO RS-232 PORT ********

	ldi	Ax, PCF8583		; load I2C adres into Ax
	ldi	Bx, $06			; Bx is loaded with Reg. number
	rcall	I2C_regread		; Load register vallue from RTC into Ax register	

	push	Ax			; Save read value on stack ( day/month info )
					; THIS VALUE WIL BE LOADED IN 2 BLOCKS !!!
	andi	Ax, 0b11100000		; remove month information
	swap 	Ax
	
	mov	Cx, Ax			; Load AX, Bx and CX register with proper
	ldi	Ax, low(dagen)		; values to locate the string of the
	ldi	Bx, high(dagen)		; current day to send on the RS-232 port
	rcall	calcpointer
	mov	Z_low, Ax		; and load it into Z_reg.
	mov	Z_high, Bx
	
	lpm				; load 1st CHR into Ax end send it
	mov	Ax, R0
	rcall	sendCHR
	adiw	Z_low, $01		; increase 16-bit pointer by one
	lpm				; and load 2nd CHR
	mov	Ax, R0
	rcall	sendCHR			; and send it to the RS-232 port
	
	ldi	Ax, $20			; send space to RS-232 port
	rcall	sendCHR
	
;********* START OF SENDING CURRENT DATE TO THE RS-232 PORT *********
	
	
	ldi	Ax, PCF8583		; load I2C adres into Ax
	ldi	Bx, $05			; Bx is loaded with day Reg. number
	rcall	I2C_regread		; Load register vallue from RTC into Ax register	
	andi	Ax, 0b00111111		; remove year info from Ax reg. 

	push	Ax			; Save read value on stack
	andi	Ax, $F0			; clear low nibble
	swap	Ax			; and move high nibble to low nibble
	subi	Ax, $D0			; and convert DEC val into ASCII val.
	rcall	sendCHR			; an send it to RS-232 port

	pop	Ax			; Reload Ax with read value
	andi	Ax, $0F			; clear high nibble
	subi	Ax, $D0			; and convert it into ASCII val
	rcall	sendCHR			; and send it to RS-232 port

	ldi	Ax, $20			; Send space to RS-232 port
	rcall	sendCHR
	
;*********** SEND CURRENT MONTH NAME TO RS-232 PORT

	pop	Ax			; reload month info from stack again
	andi	Ax, 0b00011111		; and remove day info
	rcall	DEC2HEX			; and convert DEC val into HEX value
	dec	Ax			; decrease by one ( Jan is offset 0 )
	lsl	Ax			; and multiply val by four ( monthname is 4 byte's)
	lsl	Ax
	mov	Cx, Ax			; load Ax, Bx and Cx to calculate proper
	ldi	Ax, low(maanden)	; pointer of the month string in memory
	ldi	Bx, high(maanden)
	rcall	calcpointer
	mov	Z_low, Ax		; and load it into Z-register
	mov	Z_high, Bx
	
	ldi	Bx, $04			; load Bx as cycle counter
	
monthagain:

	lpm				; load CHR from memory
	mov	Ax, R0			; into Ax register
	rcall	sendCHR			; and send it to the RS-232 port
	adiw	Z_low, $01		; increase Z-register by one
			
	dec	Bx			; decrease cycle counter
	cpi	Bx, $00			; and check for end of string
	brne	monthagain

	ldi	Ax, $20			; Load "space" info Ax
	rcall	SendCHR
	
	pop	Z_high
	pop	Z_low	
	pop	Cx
	pop	Bx
	pop	Ax


	ret

;**********************************************************************
;
; Waits until the UART is ready, and put's Ax reg. into UDR.
;
;	Ax = ASCII val. to send to RS-232 port.
;
;**********************************************************************

SendCHR:

		
UART_ready:
	sbis	USR,5			; Check for UART is ready
	rjmp	UART_ready
	
	out	UDR, Ax			; Send charakter definex in Ax to RS-232 port
	
	ret
	


;***********************************************************************
;
;	Display time on the display
;	
;	Ax	= contains start position on display
;	Bx	= contains hour vallue.
;
;***********************************************************************

disp_RTCtime:

	push	Bx			; save vallue to display on stack

	inc	Ax
	andi	Bx, $0F			; 
	subi	Bx, $D0
	push	Ax			; save display position
	rcall	dispCHR			; and display tihs vallue.
	pop	Ax
	dec	Ax

	pop	Bx
	swap	Bx			; calculate the ASCII vallue of the  10 hour's setting
	andi	Bx, $0F			; off the SW clock
	subi	Bx, $D0			; and load this ASCII vallue in Bx
	rcall	dispCHR			; display ASCII vallue
	
	ret


;**************************************************************************
;
; Routine to display the selected day informataion
;
;	Ax	= selected day information
;	Bx	= startposition on LCD
;
;**************************************************************************

disp_days:

	push	Z_low			; Save Z register SRAM pointer
	push	Z_high
	push	Ax			; Save selected day info on stack
	push	Bx			; save display position on stack

	mov	Cx, Ax			; Move selected day info into Cx reg.
	ldi	Ax, low(dayinfo)	; load Z-register with switchday data start
	ldi	Bx, high(dayinfo)	; position
	rcall	Calcpointer
	mov	Z_low,Ax
	mov	Z_high,Bx
	pop	Bx			; Reload Bx with display position
	pop	Ax			; Load Ax with day select info

	lpm				; Load R0 with the proper day settings
	mov	Cx, R0			; and move it to Cx reg.


	mov	Ax, Bx			; Load Ax with display start position 
	ldi	Bx, $08			; for printing selected SW time day's

SWnext_day:
	inc	Ax			; move cursor one place right
	dec	Bx			; decrease bit test counter.
	cpi	Bx, $00			; check for all non-selected day's
	breq	SWend_next_day
	lsr	Cx			; shift Cx register right
	brcs	SWdisp_ster		; if carry is set ( LSB = 1 ) then display
	push	Bx			; an "*" or else
	ldi	Bx, $5F			; Load "_" character in Bx register
	push	Ax
	rcall	dispCHR			; to display indicating selected day
	pop	Ax
	pop	Bx
	rjmp	SWnext_day

SWdisp_ster:
	push	Bx
	ldi	Bx, $2a			; Load "*" character in Bx register 
	push	Ax
	rcall	dispCHR			; to display indicating non-selected day
	pop	Ax
	pop	Bx
	rjmp	SWnext_day		; and go to check the next bit.

SWend_next_day:

	pop	Z_high			; and restore Z-register
	pop	Z_low

	ret
	
;**************************************************************************
;
; Routine to display a DEC value on the display
;
;	Ax	= display position to start printing at
;	Bx	= DEC value to display
;
;**************************************************************************

dispDECval:

	push	Cx

	push	Ax		; Save current display position on stack
	mov	Cx, Bx		; Save DEC val in Cx reg
	
	andi	Bx, 0b11110000	; Clear lower four bit's
	swap	Bx		; and swap the nibles
	subi	Bx, $D0		; Add $30 to get ASCII value if DEC number
	
	rcall	DispCHR		; and goto display this ASCII value
	
	pop	Ax		; reload Ax with display position
	inc	Ax		; and increase this number by one
		
	mov	Bx, Cx		; Reload Bx with org. DEC value
	andi	Bx, 0b00001111	; and clear the high nibble
	subi	Bx, $D0		; Add $30 to get ASCII value of DECnumber
	
	rcall	dispCHR		; and goto display this DEC number
	
	pop	Cx		; Restore Cx from stack


	ret
	
;**************************************************************************
;
; Routine to display a DEC value on the display
;
;	Ax	= DEC value to send to RS-232 port
;
;**************************************************************************

SendDECval:

	push	Cx

	push	Ax		; Save DEC value on stack.
	
	andi	Ax, 0b11110000	; Clear lower four bit's
	swap	Ax		; and swap the nibles
	subi	Ax, $D0		; Add $30 to get ASCII value if DEC number
	
	rcall	SendCHR		; and Send it to the RS-232 port
	
	pop	Ax		; reload Ax with DEC value
	andi	Ax, 0b00001111	; and clear the high nibble
	subi	Ax, $D0		; Add $30 to get ASCII value of DECnumber
	
	rcall	SendCHR		; and goto display this DEC number
	
	pop	Cx		; Restore Cx from stack

	ret		
	
;*********************************************************************
;
; Send channel nummer and channel status information to the RS-232 port
;
; Registers : 	Ax = Channel status info
;
; Return    :   None
;
;***********************************************************************

Send_chanstat:

	push	Cx			; Save used register vulue's 
	push	Bx			; to stack
	push	Z_low
	push	Z_high
		
	push	Ax			; Save channel/stat into to stack

	ldi	Ax, low(channel)	; Load "channel" pointer into Ax
	ldi	Bx, high(channel)	; and Bx register
	ldi	Cx, $00			; Set offset to zero
	rcall	calcpointer		; calculate memory pointer
	mov	Z_low, Ax		; and move it into Z register
	mov	Z_high, Bx
	
send_CHnum:

	lpm				; Load CHR from memory
	mov	Ax, R0			; and move it to Ax
	cpi	Ax, $00			; check if CHR is "00"
	breq	end_CHnum		; if so, then jump out
	rcall	SendCHR			; Send CHR  on RS-232 port
	adiw	Z_low, $01		; increase momory pointer by one
	rjmp	send_CHnum		; and read CHR again
		
end_CHnum:

	pop	Ax			; Reload Ax with channel state into
	push	Ax			; and save it back on stack again

	andi	Ax, $F0			; remove channel state info 
	swap	Ax
	rcall	HEX2DEC
	mov	Bx, Ax			; save DEC val into Bx reg.
	andi	Ax, $F0			; clear low nibble
	swap	Ax			; and move high nibble to low nibble
	subi	Ax, $D0			; and convert DEC val into ASCII val.
	rcall	sendCHR			; an send it to RS-232 port

	mov	Ax, Bx			; reload Ax with read value
	andi	Ax, $0F			; clear high nibble
	subi	Ax, $D0			; and convert it into ASCII val
	rcall	sendCHR			; and send it to RS-232 port

	ldi	Ax, $20			; load ASCII val for "space"
	rcall	SendCHR			; and send it ro RS-232 port
	
	ldi	Ax, $3A			; Send ":" to the RS-232 port
	rcall	SendCHR
	
	ldi	Ax, $20			; Send "SPACE" on the RS-232 port
	rcall	SendCHR
	
	pop	Ax			; reload Ax with channel/state info
	
	andi	Ax, $01			; remove channel number from data
	sbrc	Ax, 0			; skip if state bit is clear
	rjmp	state_onn		
	
	ldi	Ax, low(off)		; load "Off" string pointer into Ax
	ldi	Bx, high(off)
	rjmp	read_EEPROM	
	
state_onn:
	ldi	Ax, low(on)		; Load "On "string pointer into Ax
	ldi	Bx, high(on)

read_EEPROM:

	out	EEARL, Ax		; write EEPROM addres to read in EEPROM addres 
	out	EEARH, Bx
	sbi	EECR, EERE		; Set EEPROM Read start bit	
	
check_EEPROMready:
	in 	Ax, EECR		; load EECR status in Ax reg.
	sbrc	Ax, 0			; check if EEPROM read bit is cleared by hardware
	rjmp	check_EEPROMready	; if not, then wait until reset
	
	in	Ax, EEDR 		; Load read EEPROM data into Ax reg.
	cpi	Ax, $00
	breq	end_Statesend
	rcall	SendCHR
	in	Ax, EEARL
	inc	Ax
	cpi	Ax, $00
	brne	read_EEPROM
	in	Bx, EEARH
	inc	Bx
	rjmp	read_EEPROM
	
end_Statesend:

	pop	Z_high
	pop	Z_low
	pop	Bx
	pop	Cx


	ret