;;;
;;;  ATAPI CD-ROM Contorler    ver 1.2
;;;                                               2003/08/19  UENO Tomohiro
;;;
;;;  for ATMEL AVRStudio 4.07
;;;
;;;  Device   Micro computer : ATMEL    AVR 90S8515 with external Xtal 4MHz
;;;           LCD Panel      ; SUNLIKE  SC1602BS-B

.include	"8515def.inc"

.def	tmp		= R16
.def	tmp2		= R17

.def	ata_addr 	= R18
.def	ata_data 	= R19

.def	atapi_data_low	= R20
.def	atapi_data_high	= R21

.def	counter 	= R22
.def	play_flag	= R23

.def	total_track		= R00
.def	total_minute	= R01
.def	total_second	= R02
.def	total_frame		= R03

.def	track		= R04
.def	minute		= R05
.def	second		= R06
.def	frame		= R07

.def	playing_track	= R08
.def	playing_minute	= R09
.def	playing_second	= R10
.def	playing_frame	= R11

.def	audio_status	= R12

.def	sense_key	= R13
.def	asc		= R14
.def	ascq		= R15


;;;lcd
.equ	lcd_e		= 5	; portD
.equ	lcd_rs		= 4	; portD
;;; atapi
;;; data_low  	: PORTC
;;; data_high 	: PORTA
.equ	dior		= 6	; portD
.equ	diow		= 7	; portD
.equ	mute_out    	= 5 : portB
.equ	atapi_reset 	= 4	; portB

.equ	time_buf 	= 0x60

	rjmp	reset	; 1 $000 reset vector
	reti		; 2 $001 INT0 
	reti		; 3 $002 INT1 
	reti		; 4 $003 TIMER1 CAPT
	reti		; 5 $004 TIMER1 COMPA 
	reti		; 6 $005 TIMER1 COMPB
	reti		; 7 $006 TIMER1 OVF1 
	reti		; 8 $007 TIMER1 OVF0 
	reti		; 9 $008 SPISTC
	reti		;10 $009 UART RX 
	reti		;11 $00A UART UDRE
	reti		;12 $00B UART TX
	reti		;13 $00C ANA_COMP

RESET:	
	ldi	tmp, high(RAMEND)
	out	SPH, tmp
	ldi	tmp, low(RAMEND)
	out	SPL,tmp

	rcall	wait_10us


	; portA initialize
	ldi	tmp,0x00	; output
	out	DDRA,tmp
	ldi	tmp,0xff	; no pullup
	out	PORTA,tmp

	; portB initialize
	ldi	tmp,0xf0	; output
	out	DDRB,tmp
	ldi	tmp,0x00	; no pullup
	out	PORTB,tmp

	; portC initialize
	ldi	tmp,0x00	; output
	out	DDRC,tmp
	ldi	tmp,0xff	; no pullup
	out	PORTC,tmp

	; portD initialize
	ldi	tmp,0xff	; output
	out	DDRD,tmp
	ldi	tmp,0x00	; no pullup
	out	PORTD,tmp

	sbi	PORTD,lcd_e
	sbi	PORTD,diow
	sbi	PORTD,dior
	sbi	PORTB,atapi_reset
	cbi	PORTB,mute_out

	rcall	lcd_init

	rcall	reset_sequense
	rcall	identify_packet_device
	rcall	wait_1s

	ldi	play_flag,0
	
insert_tray:
	rcall	lcd_clear
	ldi	tmp,'S'
	rcall	lcd_put
	ldi	tmp,'e'
	rcall	lcd_put
	ldi	tmp,'a'
	rcall	lcd_put
	ldi	tmp,'r'
	rcall	lcd_put
	ldi	tmp,'c'
	rcall	lcd_put
	ldi	tmp,'h'
	rcall	lcd_put
	ldi	tmp,'i'
	rcall	lcd_put
	ldi	tmp,'n'
	rcall	lcd_put
	ldi	tmp,'g'
	rcall	lcd_put
	ldi	counter,0
no_disk_loop:
	rcall	wait_1ms
	in	tmp,PINB
	cbr	tmp,0xf7	; eject button
	cpi	tmp,0
	brne	eject_wait_loop
do_eject:
	cbi	PORTB,mute_out

	rcall	wait_1ms
	in	tmp,PINB
	cbr	tmp,0xf7	; eject button
	cpi	tmp,0
	breq	PC-3

	rcall	get_disk_status
	cpi	ata_data,0x71
	brne	PC+14

	rcall	lcd_clear	
	ldi	tmp,'C'
	rcall	lcd_put
	ldi	tmp,'l'
	rcall	lcd_put
	ldi	tmp,'o'
	rcall	lcd_put
	ldi	tmp,'s'
	rcall	lcd_put
	ldi	tmp,'e'
	rcall	lcd_put
	rcall	close_tray
	rjmp	insert_tray
			
	rcall	lcd_clear	
	ldi	tmp,'E'
	rcall	lcd_put
	ldi	tmp,'j'
	rcall	lcd_put
	ldi	tmp,'e'
	rcall	lcd_put
	ldi	tmp,'c'
	rcall	lcd_put
	ldi	tmp,'t'
	rcall	lcd_put
	rcall	open_tray
	rjmp	insert_tray

eject_wait_loop:
	ldi	tmp,20
	rcall	wait_1ms
	dec	tmp
	brne	PC-2
	rcall	request_sense
	cpi	ata_data,0x28
	breq	eject_wait_loop
	cpi	ata_data,0x29
	breq	eject_wait_loop
	cpi	ata_data,0
	breq	disk_in_loop

	rcall	get_disk_status
	cpi	ata_data,0x71
	breq	no_disk_loop

	inc	counter
	cpi	counter,250
	brne	no_disk_loop

	rcall	lcd_clear
	ldi	tmp,'N'
	rcall	lcd_put
	ldi	tmp,'o'
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put
	ldi	tmp,'D'
	rcall	lcd_put
	ldi	tmp,'i'
	rcall	lcd_put
	ldi	tmp,'s'
	rcall	lcd_put
	ldi	tmp,'k'
	rcall	lcd_put
	rjmp	no_disk_loop

disk_in_loop:
	rcall	read_toc
	mov	tmp,total_track
	inc	tmp
	rcall	get_time_table

	rcall	play
	rcall	stop

	rcall	lcd_clear
	mov	tmp,total_track
	rcall	lcd_put_decimal
	ldi	tmp,' '
	rcall	lcd_put
	ldi	tmp,'t'
	rcall	lcd_put
	ldi	tmp,'r'
	rcall	lcd_put
	ldi	tmp,'k'
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put

	mov	tmp,total_minute
	rcall	lcd_put_decimal
	ldi	tmp,':'
	rcall	lcd_put
	mov	tmp,total_second
	rcall	lcd_put_decimal
	ldi	tmp,':'
	rcall	lcd_put
	mov	tmp,total_frame
	rcall	lcd_put_decimal

	ldi	tmp,1
	mov	playing_track,tmp

put_play_number:
	ldi	tmp,0x40
	rcall	lcd_pos
	ldi	tmp,'P'
	rcall	lcd_put
	ldi	tmp,'l'
	rcall	lcd_put
	ldi	tmp,'a'
	rcall	lcd_put
	ldi	tmp,'y'
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put
	mov	tmp,playing_track
	rcall	lcd_put_decimal
	sbrc	play_flag,0
	rcall	play
		
check_button:
	rcall	wait_1ms
	in	tmp,PINB
	cbr	tmp,0xf0
	cpi	tmp,0x0f
	brne	check_button

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;put play time
	sbrs	play_flag,0
	rjmp	put_play_time_skip
	rcall	read_sub_channel
	mov	tmp,audio_status
	cpi	tmp,0x11
	breq	PC+4
	ldi	tmp,1
	mov	playing_track,tmp
	rjmp	stop_playing	
	ldi	tmp,0x45
	rcall	lcd_pos	
	mov	tmp,track
	rcall	lcd_put_decimal
	ldi	tmp,' '
	rcall	lcd_put
	mov	tmp,minute
	rcall	lcd_put_decimal
	ldi	tmp,':'
	rcall	lcd_put
	mov	tmp,second
	rcall	lcd_put_decimal
	ldi	tmp,':'
	rcall	lcd_put
	mov	tmp,frame
	rcall	lcd_put_decimal
put_play_time_skip:

	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eject
	sbis	PINB,3
	rjmp	do_eject

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ff
	sbic	PINB,2
	rjmp	skip_ff
	cp	playing_track,total_track
	breq	skip_ff
	inc	playing_track
	rjmp	put_play_number
skip_ff:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;rw
	sbic	PINB,1
	rjmp	skip_rw
	mov	tmp,playing_track
	tst	minute
	brne	PC+6
	tst	second
	brne	PC+4
	cpi	tmp,1
	breq	skip_rw
	dec	playing_track
	rjmp	put_play_number
skip_rw:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;play
	sbic	PINB,0
	rjmp	skip_play

	cpi	play_flag,0
	breq	play_skip_1
stop_playing:
	cbi	portB,mute_out
	rcall	stop
	ldi	tmp,0x45
	rcall	lcd_pos
	mov	tmp,playing_track
	rcall	lcd_put_decimal
	ldi	tmp,' '
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put
	rjmp	skip_play
play_skip_1:
	sbi	PORTB,mute_out
	rcall	play
skip_play:
	rjmp	check_button

;
; read ATA register
;	
read_ata_register:
	sbr	ata_addr,0xe0
	out	PORTD,ata_addr
	rcall	wait_10us
	cbi	PORTD,dior
	rcall	wait_10us
	in	ata_data,PINA
	sbi	PORTD,dior
	rcall	wait_10us
 	ret

;
; write ATA register
;	
write_ata_register:
	ldi	tmp,0xff
	out	DDRA,tmp
	sbr	ata_addr,0xe0
	out	PORTD,ata_addr
	out	PORTA,ata_data
	rcall	wait_10us
	cbi	PORTD,diow
	sbi	PORTD,diow
	ldi	tmp,0x00
	out	DDRA,tmp
	rcall	wait_10us
	ret

;
; read ATA data register
;
read_atapi:
	ldi	ata_addr,0xf0
	out	PORTD,ata_addr
	rcall	wait_1ms
	cbi	PORTD,dior
	rcall	wait_1ms
	in	atapi_data_high,PINC
	in	atapi_data_low,PINA
	sbi	PORTD,dior
	rcall	wait_1ms
	ret

;
; write ATA data register
;
write_atapi:
	ldi	tmp,0xff
	out	DDRA,tmp
	out	DDRC,tmp
	ldi	ata_addr,0xf0
	out	PORTD,ata_addr
	out	PORTC,atapi_data_high
	out	PORTA,atapi_data_low
	rcall	wait_10us
	cbi	PORTD,diow
	sbi	PORTD,diow
	ldi	tmp,0x00
	out	DDRA,tmp
	out	DDRC,tmp
	rcall	wait_10us
	ret

;
; reset CD-ROM
;
reset_sequense:
	cbi	PORTB,atapi_reset
	rcall	wait_1ms
	sbi	PORTB,atapi_reset
	rcall	wait_1ms
	rcall	wait_1ms
	ldi	ata_addr,0x0e
	rcall	read_ata_register
	sbrc	ata_data,7
	rjmp	PC-3
	ldi	ata_addr,0x0e
	ldi	ata_data,0xe0
	rcall	write_ata_register
	rcall	wait_1ms
	ldi	ata_addr,0x0e
	ldi	ata_data,0x02
	rcall	write_ata_register
	ldi	ata_addr,0x0e
	rcall	read_ata_register
	sbrc	ata_data,7
	rjmp	PC-3
	ret	

;
; wait until device can start sending answer data
;
check_waiting_data_from_device:
	ldi	ata_addr,0x12
	rcall	read_ata_register
	cbr	ata_data,0xfc
	cpi	ata_data,0x02
	brne	PC-4
	ldi	ata_addr,0x0e
	rcall	read_ata_register
	cbr	ata_data,0x77
	cpi	ata_data,0x08
	brne	PC-4
	ret

;
; wait until ATAPI command execution has finished
;
check_command_transfer_end:
	ldi	ata_addr,0x0e
	rcall	read_ata_register
	sbrc	ata_data,0	
	rjmp	sense_error
	mov	tmp,ata_data
	cbr	tmp,0x37
	cpi	tmp,0x40		; if not (BSY=0 and DRDY=1 and DRQ=0) then retry
	brne	check_command_transfer_end
	ldi	ata_addr,0x12
	rcall	read_ata_register
	mov	tmp,ata_data
	cbr	tmp,0xf8
	cpi	tmp,0x03		; fi not (REL=0 and I/O=1 and C/D=1) then retry
	brne	check_command_transfer_end
	ret

;
; identify packet device
;	
identify_packet_device:
	; device selection protocol
	ldi	ata_addr,0x0e
	rcall	read_ata_register
	andi	ata_data,0x88
	cpi	ata_data,0x00
	brne	PC-4
	ldi	ata_addr,0x16
	ldi	ata_data,0x00
	rcall	write_ata_register
	nop
	ldi	ata_addr,0x0e
	rcall	read_ata_register
	andi	ata_data,0x88
	cpi	ata_data,0x00
	brne	PC-4

	rcall	lcd_clear
	ldi	tmp,'-'
	rcall	lcd_put
	ldi	tmp,'D'
	rcall	lcd_put
	ldi	tmp,'e'
	rcall	lcd_put
	ldi	tmp,'v'
	rcall	lcd_put
	ldi	tmp,'i'
	rcall	lcd_put
	ldi	tmp,'c'
	rcall	lcd_put
	ldi	tmp,'e'
	rcall	lcd_put
	ldi	tmp,'-'
	rcall	lcd_put

	ldi	tmp,0x40
	rcall	lcd_pos

	ldi	ata_addr,0x16
	ldi	ata_data,0x00
	rcall	write_ata_register
	ldi	ata_addr,0x17
	ldi	ata_data,0xa1
	rcall	write_ata_register

	ldi	ata_addr,0x0e
	rcall	read_ata_register
	andi	ata_data,0x88
	cpi	ata_data,0x08
	brne	PC-4

	ldi	counter,0
identify_packet_device_loop:

	rcall	read_atapi
	cpi	counter,27
	brcs	PC+7
	cpi	counter,27+8
	brcc	PC+5
	mov	tmp,atapi_data_high
	rcall	lcd_put
	mov	tmp,atapi_data_low
	rcall	lcd_put
	inc	counter
	brne	identify_packet_device_loop

	;;; set features command
	ldi	ata_addr,0x0e
	ldi	ata_data,0x0a
	rcall	write_ata_register
	ldi	ata_addr,0x11
	ldi	ata_data,0x03
	rcall	write_ata_register
	ldi	ata_addr,0x12
	ldi	ata_data,0x01
	rcall	write_ata_register
	ldi	ata_addr,0x16
	ldi	ata_data,0x00
	rcall	write_ata_register
	ldi	ata_addr,0x17
	ldi	ata_data,0xef
	rcall	write_ata_register
	ret
;
; send atapi packet command
;
send_atapi_command_packet:
	ldi	ata_addr,0x0e
	rcall	read_ata_register
	sbrc	ata_data,7
	rjmp	PC-3

	ldi	ata_addr,0x0e
	ldi	ata_data,0x0a
	rcall	write_ata_register
	ldi	ata_addr,0x11
	ldi	ata_data,0x00
	rcall	write_ata_register
	ldi	ata_addr,0x13
	ldi	ata_data,0x00
	rcall	write_ata_register
	ldi	ata_addr,0x14
	ldi	ata_data,0xff
	rcall	write_ata_register
	ldi	ata_addr,0x15
	ldi	ata_data,0xff
	rcall	write_ata_register
	ldi	ata_addr,0x16
	ldi	ata_data,0x00
	rcall	write_ata_register
	ldi	ata_addr,0x17
	ldi	ata_data,0xa0
	rcall	write_ata_register

	ldi	ata_addr,0x12
	rcall	read_ata_register
	cbr	ata_data,0xf8
	cpi	ata_data,0x01
	brne	PC-4
	ldi	ata_addr,0x0e
	rcall	read_ata_register
	cbr	ata_data,0x77
	cpi	ata_data,0x08
	brne	PC-4
	ret

;
; request sense
;
request_sense:
	rcall	send_atapi_command_packet

	;;; test unit ready
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi

	rcall	send_atapi_command_packet

	;;; request sense
	ldi	atapi_data_low ,0x03
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,18
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	rcall	check_waiting_data_from_device

	ldi	ata_data,0		; set return value = 0

	ldi	ata_addr,0x10
	rcall	read_atapi	;0/1
	rcall	read_atapi	;2/3
		
	cbr	atapi_data_low,0xf0
	mov	ata_data,atapi_data_low
	rcall	read_atapi	;4/5
	rcall	read_atapi	;6/7
	rcall	read_atapi	;8/9
	rcall	read_atapi	;10/11
	rcall	read_atapi	;12/13
	cpi	atapi_data_low,0x28
	brne	PC+2
	mov	ata_data,atapi_data_low
	cpi	atapi_data_low,0x29
	brne	PC+2
	mov	ata_data,atapi_data_low
	rcall	read_atapi	;14/15
	rcall	read_atapi	;16/17
	ret

;
; get disk status
;  return value: ata_data, 0x71=tray is opened
;	
get_disk_status:
	rcall	send_atapi_command_packet

	;;; mode_sense
	ldi	atapi_data_low ,0x5a
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x0d	; cdrom pages
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,8+8
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms

	rcall	read_atapi
	rcall	read_atapi
	push	atapi_data_low
	rcall	read_atapi
	rcall	read_atapi
	rcall	read_atapi
	rcall	read_atapi
	rcall	read_atapi
	rcall	read_atapi
	pop	ata_data
	ret
;
; open tray
;
open_tray:
	rcall	send_atapi_command_packet

	;;; prevent/allow medium removal
	ldi	atapi_data_low ,0x1e
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
		
	rcall	send_atapi_command_packet

	;;; start/stop unit
	ldi	atapi_data_low ,0x1b
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x02
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	rcall	check_command_transfer_end

	ldi	play_flag,0
	ret	

;
; close tray
;	
close_tray:
	rcall	send_atapi_command_packet

	;;; prevent/allow medium removal
	ldi	atapi_data_low ,0x1e
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
		
	rcall	send_atapi_command_packet

	;;; start/stop unit
	ldi	atapi_data_low ,0x1b
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x03
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	rcall	check_command_transfer_end

	ldi	play_flag,0
	ret	
	
;
; read toc
;
read_toc:
	rcall	send_atapi_command_packet

	;;; prevent/allow medium removal
	ldi	atapi_data_low ,0x43
	ldi	atapi_data_high,0x02
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0xff
	rcall	write_atapi
	ldi	atapi_data_low ,0xff
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	rcall	check_waiting_data_from_device

	rcall	read_atapi
	rcall	read_atapi

	ldi	tmp,1
	mov	playing_track,tmp

	ldi	tmp,0
	mov	total_track,tmp

	ldi	YH,high(time_buf)
	ldi	YL,low(time_buf)
loop_read_toc:	
	rcall	read_atapi
	rcall	read_atapi
	mov	track,atapi_data_low
	rcall	read_atapi
	mov	audio_status,atapi_data_low
	mov	minute,atapi_data_high
	rcall	read_atapi
	mov	second,atapi_data_low
	mov	frame,atapi_data_high

	ldi	tmp,0x00
	cp	audio_status,tmp
	brne	loop_read_toc

	st	Y+,minute
	st	Y+,second
	st	Y+,frame

	ldi	tmp,0xaa
	cp	track,tmp
	breq	PC+3

	inc	total_track
	rjmp	loop_read_toc

	rcall	check_command_transfer_end
	mov	total_minute,minute
	mov	total_second,second
	mov	total_frame,frame
	ret

;
; return track MSF
;
get_time_table:
	dec	tmp
	push	tmp2
	ldi	tmp2,0
	ldi	YH,high(time_buf)
	ldi	YL,low(time_buf)
	add	YL,tmp
	adc	YH,tmp2	
	add	YL,tmp
	adc	YH,tmp2	
	add	YL,tmp
	adc	YH,tmp2	
	
	ld	minute,Y+
	ld	second,Y+
	ld	frame,Y+
	
	pop	tmp2
	ret			

;
; play track
;	
play:
	mov	tmp,playing_track
	rcall	get_time_table
	mov	playing_minute,minute
	mov	playing_second,second
	mov	playing_frame,frame

	rcall	send_atapi_command_packet

	;;; play_audio_msf
	ldi	atapi_data_low ,0x47
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	mov	atapi_data_high,minute
	rcall	write_atapi
	mov	atapi_data_low ,second
	mov	atapi_data_high,frame
	rcall	write_atapi
	mov	atapi_data_low ,total_minute
	mov	atapi_data_high,total_second
	rcall	write_atapi
	mov	atapi_data_low ,total_frame
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	rcall	check_command_transfer_end

	ldi	play_flag,1	
	ret

;
; read sub channel
;
read_sub_channel:
	rcall	send_atapi_command_packet

	;;; read sub-channel
	ldi	atapi_data_low ,0x42
	ldi	atapi_data_high,0x02
	rcall	write_atapi
	ldi	atapi_data_low ,0x40
	ldi	atapi_data_high,0x01
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0xff
	rcall	write_atapi
	ldi	atapi_data_low ,0xff
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	rcall	check_waiting_data_from_device

	rcall	read_atapi
	mov	audio_status,atapi_data_high
	rcall	read_atapi
	rcall	read_atapi
	rcall	read_atapi
	mov	track,atapi_data_low
	rcall	read_atapi
	rcall	read_atapi
	rcall	read_atapi
	mov	minute,atapi_data_high
	rcall	read_atapi
	mov	second,atapi_data_low
	mov	frame,atapi_data_high
	ret

;
; stop CD
;
stop:
	rcall	send_atapi_command_packet

	;;; play_audio_msf
	ldi	atapi_data_low ,0x4e
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	rcall	check_command_transfer_end
	
	ldi	play_flag,0
	ret

;
; sense error code
;
sense_error:
	rcall	send_atapi_command_packet

	;;; request sense
	ldi	atapi_data_low ,0x03
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,18
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
	ldi	atapi_data_low ,0x00
	ldi	atapi_data_high,0x00
	rcall	write_atapi
		
	rcall	check_waiting_data_from_device

	ldi	ata_addr,0x10
	rcall	read_atapi	;0/1
	rcall	lcd_put_hex
	rcall	read_atapi	;2/3
	mov	sense_key,atapi_data_low
	rcall	read_atapi	;4/5
	rcall	read_atapi	;6/7
	rcall	read_atapi	;8/9
	rcall	read_atapi	;10/11
	rcall	read_atapi	;12/13
	mov	asc,atapi_data_low
	mov	ascq,atapi_data_high
	rcall	read_atapi	;14/15
	rcall	read_atapi	;16/17
	ret

;
; print error code (sense_key,asc,ascq)
;
print_error:
	ldi	tmp,0x40
	rcall	lcd_pos
	ldi	tmp,'E'
	rcall	lcd_put
	ldi	tmp,'r'
	rcall	lcd_put
	ldi	tmp,'r'
	rcall	lcd_put
	ldi	tmp,'o'
	rcall	lcd_put
	ldi	tmp,'r'
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put

	mov	tmp,sense_key
	rcall	lcd_put_hex
	mov	tmp,asc
	rcall	lcd_put_hex
	mov	tmp,ascq
	rcall	lcd_put_hex
	
;	rjmp	PC
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;
; LCD (SUNLIKE SC1602BS-B) initialize
;
lcd_init:
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
 	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	ldi	tmp,0x03
	rcall	lcd_control_out
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	ldi	tmp,0x03
	rcall	lcd_control_out
	rcall	wait_1ms
	ldi	tmp,0x03
	rcall	lcd_control_out
	rcall	wait_1ms
	ldi	tmp,0x02
	rcall	lcd_control_out
	ldi	tmp,0x28
	rcall	lcd_control
	ldi	tmp,0x0c
	rcall	lcd_control
	ldi	tmp,0x06
	rcall	lcd_control
	ldi	tmp,0x01
	rcall	lcd_control
	rcall	lcd_clear
	ret

;
; LCD screen clear and move position (0,0)
;
lcd_clear:
	ldi	tmp,0x01
	rcall	lcd_control
	ret
	
;
; LCD move position  :  (0,0)=0x00, (0,1)=0x01, (1,0)=0x40
;
lcd_pos:
	sbr	tmp,0x80
	rcall	lcd_control
	ret

;
; LCD put character
;
lcd_put:
	push	tmp
	swap	tmp	
	rcall	lcd_data_out
	pop	tmp
	rcall	lcd_data_out
	ret

;
; LCD put number in hex
;
lcd_put_hex:
	ldi	tmp2,7
	push	tmp
	swap	tmp
	cbr	tmp,0xf0
	sbr	tmp,0x30
	cpi	tmp,0x3a
	brcs	PC+2
	add	tmp,tmp2
	rcall	lcd_put
	pop	tmp
	cbr	tmp,0xf0
	sbr	tmp,0x30
	cpi	tmp,0x3a
	brcs	PC+2
	add	tmp,tmp2
	rcall	lcd_put
	ret

;
; LCD put number in decimal
;
lcd_put_decimal:
	mov	tmp2,tmp
	ldi	tmp,0
lcd_put_decimal_loop:
	cpi	tmp2,10
	brlo	lcd_put_decimal_skip
	subi	tmp2,10
	inc	tmp
	rjmp	lcd_put_decimal_loop
lcd_put_decimal_skip:
	sbr	tmp,0x30
	rcall	lcd_put
	mov	tmp,tmp2
	sbr	tmp,0x30
	rcall	lcd_put
	ret

lcd_control:
	push	tmp
	swap	tmp	
	rcall	lcd_control_out
	pop	tmp
	rcall	lcd_control_out
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	ret

lcd_control_out:
	cbr	tmp,0x10	;rs
	sbr	tmp,0xe0	;e,dior,diow
	out	PORTD,tmp
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	cbi	PORTD,lcd_e
	sbi	PORTD,lcd_e
	rcall	wait_1ms
	ret

lcd_data_out:
	sbr	tmp,0xf0	;rs,e,dior,diow
	out	PORTD,tmp
	rcall	wait_1ms
	cbi	PORTD,lcd_e
	sbi	PORTD,lcd_e
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;
; wait 1 second
;
wait_1s:
	push	tmp

	ldi	tmp,250
wait_1s_a:
	rcall	wait_1ms
	dec	tmp
	brne	wait_1s_a

	ldi	tmp,250
wait_1s_b:
	rcall	wait_1ms
	dec	tmp
	brne	wait_1s_b

	ldi	tmp,250
wait_1s_c:
	rcall	wait_1ms
	dec	tmp
	brne	wait_1s_c

	ldi	tmp,250
wait_1s_d:
	rcall	wait_1ms
	dec	tmp
	brne	wait_1s_d

	pop	tmp	
	ret
	
;
; wait 1 ms
;
wait_1ms:
	push	tmp
	ldi	tmp,255
wait_1ms_loop:
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	dec	tmp
	brne	wait_1ms_loop
	pop	tmp
	ret
	

;
; wait 10 us
;
wait_10us:
	push	tmp
	ldi	tmp,10
	nop
	dec	tmp
	brne	PC-2
	pop	tmp
	ret
	

