;;;
;;;  ATAPI CD-ROM Contorler    ver 2.6
;;;                                               2004/05/30  UENO Tomohiro
;;;
;;;  for ATMEL AVRStudio 4.07
;;;
;;;  Device   Micro computer : ATMEL    AVR 90S8515 with external Xtal 4MHz
;;;           LCD Panel      ; SUNLIKE  SC1602BS*B / Noritake CU16025ECPB-W6J

.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	close_play_flag	= R24

.def	lcd_track	= R25
.def	lcd_minute	= R26
.def	lcd_second	= R27

.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	; portB
.equ	lcd_rs		= 4	; portB
;;; atapi
;;; data_low  	: PORTD
;;; data_high 	: PORTC
.equ	dior		= 6	; portB
.equ	diow		= 7	; portB
.equ	atapi_reset 	= 3	; portA

.equ	time_buf 	= 0x60

;;; button
.equ	eject_button	= 7
.equ	foward_button	= 6
.equ	rewind_button	= 5
.equ	play_button	= 4

	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,0x0f	; output
	out	DDRA,tmp
	ldi	tmp,0xff	; no pullup
	out	PORTA,tmp

	; portB initialize
	ldi	tmp,0xff	; 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,0x00	; output
	out	DDRD,tmp
	ldi	tmp,0x00	; no pullup
	out	PORTD,tmp

	sbi	PORTB,lcd_e
	sbi	PORTB,diow
	sbi	PORTB,dior
	sbi	PORTA,atapi_reset

	rcall	lcd_init

	rcall	reset_sequense
	rcall	identify_packet_device
	rcall	wait_1s

	ldi	play_flag,0
	ldi	close_play_flag,0
	
media_check:
	rcall	lcd_clear
	ldi	tmp,'D'
	rcall	lcd_put
	ldi	tmp,'i'
	rcall	lcd_put
	ldi	tmp,'s'
	rcall	lcd_put
	ldi	tmp,'c'
	rcall	lcd_put
	ldi	tmp,' '
	rcall	lcd_put
	ldi	tmp,'c'
	rcall	lcd_put
	ldi	tmp,'h'
	rcall	lcd_put
	ldi	tmp,'e'
	rcall	lcd_put
	ldi	tmp,'c'
	rcall	lcd_put
	ldi	tmp,'k'
	rcall	lcd_put
	ldi	tmp,'i'
	rcall	lcd_put
	ldi	tmp,'n'
	rcall	lcd_put
	ldi	tmp,'g'
	rcall	lcd_put

	ldi	counter,0
tray_check_loop:
	sbis	PINA,eject_button
	rjmp	do_eject

	rcall	wait_10ms
	rcall	wait_10ms
	rcall	request_sense
	cpi	ata_data,0x28
	breq	tray_check_loop
	cpi	ata_data,0x29
	breq	tray_check_loop
	cpi	ata_data,0
	breq	toc_check
	inc	counter
	cpi	counter,250
	brne	tray_check_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,'c'
	rcall	lcd_put
	rjmp	tray_check_loop


do_eject:
	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
	clr	close_play_flag
do_eject_loop:
	in	tmp,PINA
	cbr	tmp,0x7f	; eject button
	cpi	tmp,0
	brne	PC+3
	rcall	close_tray
	rjmp	media_check

	in	tmp,PINA
	cbr	tmp,0xef	; play button
	cpi	tmp,0
	brne	PC+4
	rcall	close_tray
	ldi	close_play_flag,1
	rjmp	media_check

	rcall	get_disk_status

	cpi	ata_data,0x70
	breq	tray_check_loop
	cpi	ata_data,0x71
	breq	do_eject_loop
	cpi	ata_data,0x00
	breq	do_eject_loop
	cpi	ata_data,0x30
	breq	do_eject_loop

toc_check:
	rcall	read_toc
	mov	tmp,total_track
	inc	tmp
	rcall	get_time_table	; total track time table

	rcall	play	
	mov	tmp,close_play_flag
	cpi	tmp,0
	breq	PC+3
	clr	close_play_flag
	rjmp	PC+2
	rcall	stop

	ldi	tmp,1
	mov	playing_track,tmp
put_play_number:
	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,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
	ldi	lcd_track,0xff
	ldi	lcd_minute,0xff
	ldi	lcd_second,0xff

button_check:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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
	mov	playing_track,track
	rcall	print_play_number
put_play_time_skip:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eject
	sbic	PINA,7
	rjmp	skip_eject
	sbis	PINA,7
	rjmp	PC-1
	rjmp	do_eject
skip_eject:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ff
	sbic	PINA,6
	rjmp	skip_ff

	cpi	play_flag,1
	breq	PC+11

	cp	playing_track,total_track
	breq	skip_ff
	inc	playing_track
	cpi	play_flag,0	
	breq	PC+3
	rcall	stop
	rcall	play
	sbis	PINA,6
	rjmp	PC-1
	rjmp	put_play_number

	ldi	counter,0
	rcall	wait_10ms
	sbis	PINA,6
	rjmp	PC+2
	rjmp	PC-14
	inc	counter
	cpi	counter,50
	brne	PC-6
loop_ff:
	push	minute
	push	second
	mov	tmp,track
	rcall	get_time_table
	pop	tmp
	add	second,tmp
	pop	tmp
	add	minute,tmp
	inc	second
	inc	second
	inc	second
	inc	second
	mov	tmp,second
	cpi	tmp,60
	brlo	PC+4
	subi	tmp,60
	mov	second,tmp
	inc	minute
	rcall	play_sub
	rcall	read_sub_channel
	rcall	print_play_number
	sbis	PINA,6
	rjmp	loop_ff
skip_ff:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;rw
	sbic	PINA,5
	rjmp	skip_rw

	cpi	play_flag,1
	breq	PC+11

	mov	tmp,playing_track
	cpi	tmp,1
	breq	PC+2
	dec	playing_track
	sbis	PINA,5
	rjmp	PC-1
	rcall	wait_10ms
	rcall	wait_10ms
	rcall	wait_10ms
	rjmp	put_play_number

	ldi	counter,0
	rcall	wait_10ms
	sbis	PINA,5
	rjmp	PC+2
	rjmp	PC+5
	inc	counter
	cpi	counter,50
	brne	PC-6
	rjmp	loop_rw

	tst	minute
	brne	PC+7
	mov	tmp,second
	cpi	tmp,1
	brge	PC+5
	ldi	tmp,1
	cp	playing_track,tmp
	breq	PC+2
	dec	playing_track
	rcall	stop
	rcall	play
	sbis	PINA,5
	rjmp	PC-1
	rjmp	put_play_number
loop_rw:
	tst	minute
	brne	PC+14
	mov	tmp,second
	cpi	tmp,3
	brge	PC+11	
	clr	second
	ldi	tmp,1
	clr	minute
	clr	second
	clr	frame
	rcall	print_play_number
	sbis	PINA,5
	rjmp	PC-1
	rcall	play
	rjmp	put_play_number

	push	second
	push	minute
	mov	tmp,lcd_track
	rcall	get_time_table
	pop	tmp
	add	minute,tmp
	pop	tmp
	add	second,tmp
	mov	tmp,second
	cpi	tmp,60
	brlo	PC+4
	subi	tmp,60
	mov	second,tmp
	inc	minute
	mov	tmp,second
	cpi	tmp,3
	brlt	PC+4
	subi	tmp,3
	mov	second,tmp
	rjmp	PC+12
	mov	tmp,minute
	cpi	tmp,0
	brne	PC+6
	rcall	stop
	rcall	play
	sbis	PINA,5
	rjmp	PC-1
	rjmp	put_play_number
	dec	minute
	ldi	tmp,-3+60
	add	second,tmp

	rcall	play_sub
	rcall	read_sub_channel
	rcall	print_play_number
	mov	playing_track,lcd_track
	sbis	PINA,5
	rjmp	loop_rw
skip_rw:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;play
	sbic	PINA,4
	rjmp	skip_play

	cpi	play_flag,0
	brne	stop_playing
	rcall	play
	sbis	PINA,4
	rjmp	PC-1
	rjmp	skip_play
stop_playing:
	rcall	stop
	sbis	PINA,4
	rjmp	PC-1
	rjmp	put_play_number
skip_play:

	rjmp	button_check


;
; read ATA register
;	
read_ata_register:
	sbr	ata_addr,0xe0
	out	PORTB,ata_addr
	rcall	wait_10us
	cbi	PORTB,dior
	rcall	wait_10us
	in	ata_data,PIND
	sbi	PORTB,dior
	rcall	wait_10us
 	ret

;
; write ATA register
;	
write_ata_register:
	ldi	tmp,0xff
	out	DDRD,tmp
	sbr	ata_addr,0xe0
	out	PORTB,ata_addr
	out	PORTD,ata_data
	rcall	wait_10us
	cbi	PORTB,diow
	sbi	PORTB,diow
	ldi	tmp,0x00
	out	DDRD,tmp
	rcall	wait_10us
	ret

;
; read ATA data register
;
read_atapi:
	ldi	ata_addr,0xf0
	out	PORTB,ata_addr
	rcall	wait_1ms
	cbi	PORTB,dior
	rcall	wait_1ms
	in	atapi_data_high,PINC
	in	atapi_data_low,PIND
	sbi	PORTB,dior
	rcall	wait_1ms
	ret

;
; write ATA data register
;
write_atapi:
	ldi	tmp,0xff
	out	DDRD,tmp
	out	DDRC,tmp
	ldi	ata_addr,0xf0
	out	PORTB,ata_addr
	out	PORTC,atapi_data_high
	out	PORTD,atapi_data_low
	rcall	wait_10us
	cbi	PORTB,diow
	sbi	PORTB,diow
	ldi	tmp,0x00
	out	DDRD,tmp
	out	DDRC,tmp
	rcall	wait_10us
	ret

;
; reset CD-ROM
;
reset_sequense:
	rcall	wait_10ms
	cbi	PORTA,atapi_reset
	rcall	wait_10ms
	sbi	PORTA,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

	ldi	tmp,1
	mov	playing_track,tmp
	ldi	tmp,0
	mov	total_track,tmp

	ldi	YH,high(time_buf)
	ldi	YL,low(time_buf)

	rcall	read_atapi
	rcall	read_atapi
loop_read_toc:
	rcall	read_atapi
	mov	audio_status,atapi_data_high
	rcall	read_atapi
	mov	track,atapi_data_low
	rcall	read_atapi
	mov	minute,atapi_data_high
	rcall	read_atapi
	mov	second,atapi_data_low
	mov	frame,atapi_data_high

	ldi	tmp,0xaa
	cp	track,tmp
	breq	PC+11

	ldi	tmp,0x0f
	and	audio_status,tmp
 	ldi	tmp,0x00
	cp	audio_status,tmp
	brne	PC-16

	st	Y+,minute
	st	Y+,second
	st	Y+,frame
	inc	total_track

	rjmp	loop_read_toc

	mov	total_minute,minute
	mov	total_second,second
	mov	total_frame,frame

	rcall	check_command_transfer_end
	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	play_sub
	
	ldi	play_flag,1	
	ret

play_sub:
	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
	ret

print_play_number:
	cp	track,lcd_track
	breq	PC+6
	mov	lcd_track,track
	ldi	tmp,0x45
	rcall	lcd_pos	
	mov	tmp,track
	rcall	lcd_put_decimal

	cp	minute,lcd_minute
	breq	PC+8
	mov	lcd_minute,minute
	ldi	tmp,0x48
	rcall	lcd_pos	
	mov	tmp,minute
	rcall	lcd_put_decimal
	ldi	tmp,':'
	rcall	lcd_put

	cp	second,lcd_second
	breq	PC+8
	mov	lcd_second,second
	ldi	tmp,0x4b
	rcall	lcd_pos	
	mov	tmp,second
	rcall	lcd_put_decimal
	ldi	tmp,':'
	rcall	lcd_put

	ldi	tmp,0x4e
	rcall	lcd_pos	
	mov	tmp,frame
	rcall	lcd_put_decimal
	ret
;
; pause
;	
pause:
	; tmp=0/1 : pause/resume
	push	tmp

	rcall	send_atapi_command_packet

	;;; pause/resume
	ldi	atapi_data_low ,0x4B
	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
	pop	tmp
	mov	atapi_data_low ,tmp
	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

	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:
	ldi	counter,0x250
	rcall	wait_1ms
	dec	counter
	brne	PC-2
	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	PORTB,tmp
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	rcall	wait_1ms
	cbi	PORTB,lcd_e
	sbi	PORTB,lcd_e
	rcall	wait_1ms
	ret

lcd_data_out:
	sbr	tmp,0xf0	;rs,e,dior,diow
	out	PORTB,tmp
	rcall	wait_1ms
	cbi	PORTB,lcd_e
	sbi	PORTB,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
	
;
; wait 10 ms
;
wait_10ms:
	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
	ret
	


