Source file: /~heha/basteln/PC/kvm/usbconv.zip/usbconv.asm

;------------------------------------------------------------------------------
; usbconv for AT90S2313  Ver 1.0  2005.03.10 by K.Ishikawa
;------------------------------------------------------------------------------

	.include "2313def.inc"

;------------------------------------------------------------------------------
;	AVR Port Assign List
;
;	PortB bit0  LED
;	      bit1  Select 0:Mouse 1:Keyboard 
;	      bit2  
;	      bit3  
;	      bit4  
;	      bit5  (MOSI)
;	      bit6  (MISO)
;	      bit7  (SCK)
;	PortD bit0  RxD
;	      bit1  TxD
;	      bit2  USB BUS D+
;	      bit3  USB BUS D-
;	      bit4  
;	      bit5  
;	      bit6  

;------------------------------------------------------------------------------

	.def	reg_0		= r10
	.def	reg_1		= r11
	.def	reg_2		= r12
	.def	reg_3		= r13
	.def	keynum		= r14
	.def	keysts		= r15
	.def	keynum_n	= r16
	.def	uartwbuf	= r17
	.def	uartrbuf	= r18
	.def	icount		= r19
	.def	connect		= r20
	.def	tcount		= r21
	.def	arg1		= r22
	.def	arg2		= r23
	.def	tmp1		= r24
	.def	tmp2		= r25

	.equ    UARTBUF		= $60	; Start UART Buffer Location
	.equ    USBBUFSTART	= $66	; Start USB Buffer Location
	.equ    INTERVAL	= 24	; Interrupt Inverval(ms)

;------------------------------------------------------------------------------


;------------------------------------------------------------------------------

	rjmp	MAIN		; Reset Handler
	rjmp	EXT_INT0	; IRQ0 Handler
	rjmp	EXT_INT1	; IRQ0 Handler
	rjmp	TIM1_CAPT	; Timer1 Capture Handler
	rjmp	TIM1_COMP	; Timer1 Compare Handler
	rjmp	TIM1_OVF	; Timer1 Overflow Handler
	rjmp	TIM0_OVF	; Timer0 Overflow Handler
	rjmp	UART_RXC	; UART RX Complete Handler
	rjmp	UART_DRE	; UDR Empty Handler
	rjmp	UART_TXC	; UART TX Complete Handler
	rjmp	ANA_COMP	; Analog Comparator Handler

;------------------------------------------------------------------------------

EXT_INT0:
EXT_INT1:
TIM1_CAPT:
TIM1_COMP:
TIM1_OVF:
UART_RXC:
UART_DRE:
UART_TXC:
ANA_COMP:
	reti

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------

DATA_EOP:
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_ACK:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x04, 0x04
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_SETUP_TOKEN_0:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x08, 0x08, 0x08, 0x04, 0x04, 0x08, 0x04
	.db		0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04
	.db		0x08, 0x04, 0x08, 0x04, 0x04, 0x08, 0x04, 0x08
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_SET_ADDRESS_1:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04, 0x04
	.db		0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04
	.db		0x04, 0x08, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x08, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08
	.db		0x08, 0x04, 0x04, 0x08, 0x04, 0x04, 0x08, 0x04
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_DATA_IN_0_0:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x04
	.db		0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04
	.db		0x08, 0x04, 0x08, 0x04, 0x04, 0x08, 0x04, 0x08
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_SETUP_TOKEN_1:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x08, 0x08, 0x08, 0x04, 0x04, 0x08, 0x04
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_SET_CONFIGURATION_1:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04, 0x04
	.db		0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04
	.db		0x04, 0x08, 0x04, 0x04, 0x08, 0x04, 0x08, 0x04
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x08, 0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x08
	.db		0x08, 0x04, 0x04, 0x08, 0x04, 0x04, 0x08, 0x04
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_DATA_IN_1_0:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x04
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x08
	.db		0x04, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08
	.db		0x02, 0x02, 0x08, 0x08
DATA_PKT_DATA_IN_1_1:
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x04, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x04
	.db		0x04, 0x08, 0x04, 0x08, 0x04, 0x08, 0x04, 0x04
	.db		0x08, 0x04, 0x08, 0x08, 0x08, 0x04, 0x04, 0x08
	.db		0x02, 0x02, 0x08, 0x08

	.org	0x100
DATA_USAGE_ID_TABLE:
	.db		0x00, 0x00, 0x00, 0x00, 'a',  'b',  'c',  'd'
	.db		'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l'
	.db		'm',  'n',  'o',  'p',  'q',  'r',  's',  't'
	.db		'u',  'v',  'w',  'x',  'y',  'z',  '1',  '2'
	.db		'3',  '4',  '5',  '6',  '7',  '8',  '9',  '0'
	.db		0x0D, 0x1B, 0x7F, 0x17, ' ',  '-',  '^',  '@'
	.db		'[',  0x5C, ']',  0x3B, ':',  0x00, 0x2C, '.'
	.db		'/',  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
DATA_USAGE_ID_TABLE_SHIFT:
	.db		0x00, 0x00, 0x00, 0x00, 'A',  'B',  'C',  'D'
	.db		'E',  'F',  'G',  'H',  'I',  'J',  'K',  'L'
	.db		'M',  'N',  'O',  'P',  'Q',  'R',  'S',  'T'
	.db		'U',  'V',  'W',  'X',  'Y',  'Z',  '!',  0x22
	.db		0x23, '$',  '%',  '&',  0x27, '(',  ')',  0x00
	.db		0x0D, 0x1B, 0x7F, 0x17, ' ',  '=',  '~',  0x60
	.db		'{',  '|',  '}',  '+',  '*',  0x00, '<',  '>'
	.db		'?',  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
DATA_BPS:
	.db		0x9B, 0x4D, 0x33, 0x26, 0x19, 0x13, 0x0C, 0x06
;	.db		0x9B		; PB4-PB2 000   4800bps
;	.db		0x4D		;         001   9600bps
;	.db		0x33		;         010  14400bps
;	.db		0x26		;         011  19200bps
;	.db		0x19		;         100  28800bps 
;	.db		0x13		;         101  38400bps
;	.db		0x0C		;         110  57600bps
;	.db		0x06		;         111 115200bps

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------

MAIN:
	; **** Initialize Stack Pointer ****
	ldi		tmp1, LOW(RAMEND)	; Stack Pointer Setup
	out		SPL, tmp1			; Stack Pointer Low Byte	
	; **** Turn off Watchdog timer ****
	ldi		tmp1, 0x18			; 
	out		WDTCR, tmp1			; 
	ldi		tmp1, 0x10			; 
	out		WDTCR, tmp1			;
	; **** Initialize Comparator ****
	ldi		tmp1, 0x80			; Disable comparator to save power
	out		ACSR, tmp1			; 
	; **** Initialize I/O Port ****
	ldi		tmp1, 0x01			; Set PB0 as Output Mode
	out		DDRB, tmp1
	ldi		tmp1, 0x1E			; LED ON
	out		PORTB, tmp1
	ldi		tmp1, 0x00			; Set PD0-6 as Input Mode
	out		DDRD, tmp1
	ldi		tmp1, 0x00			; PD2-3 HI-Z
	out		PORTD, tmp1
	; **** Initialize UART ****
	ldi		ZH, HIGH(DATA_BPS*2); Set Baud Rate
	ldi		ZL, LOW(DATA_BPS*2)
	in		tmp1, PINB
	lsr		tmp1
	lsr		tmp1
	andi	tmp1, 0x07
	add		ZL, tmp1
	lpm
	out		UBRR, r0			; UART Baud rate generator
	ldi		tmp1, 0x18			; UART Interrupt Disables
	out		UCR, tmp1			; RX Enable, TX Enable, 9-Bit Disable
	ldi		tmp1, 0x00			; Dummy write
	out		UDR, tmp1
	; **** Initialize Timer 0 ****
	ldi		tcount, 0x00			; 
	ldi		tmp1, 0x02			; Enable Timer0 Overflow Interrupt
	out		TIMSK, tmp1
	ldi		tmp1, 69			; 1ms Timer Count
	out		TCNT0, tmp1
	ldi		tmp1, 0x03			; CK/64, Timer Start
	out		TCCR0, tmp1
	sei							; Enable Global Interrupt
	; **** Initialize Register ****
	ldi		tmp1, 0
	mov		reg_0, tmp1
	ldi		tmp1, 1
	mov		reg_1, tmp1
	ldi		tmp1, 2
	mov		reg_2, tmp1
	ldi		tmp1, 3
	mov		reg_3, tmp1
	ldi		connect, 0			; Set State Disconnect
	ldi		tcount, 0
	ldi		icount, 0
	ldi		uartrbuf, 0
	ldi		uartwbuf, 0
	mov		keynum, reg_0
	; **** Power On Wait ****
	ldi		arg1, 10			; 1sec wait
	rcall	DELAY_100MS
	ldi		tmp1, 0x1F			; LED OFF
	out		PORTB, tmp1
	
	; **** Main Loop ****
MAIN_LOOP:
	ldi		arg1, 1				; 1ms wait
	rcall	DELAY_1MS
	cpi		connect, 0			; Check State
	breq	MAIN_LOOP_DISCONNECT
	rjmp	MAIN_CONNECT
MAIN_LOOP_DISCONNECT:
	rjmp	MAIN_DISCONNECT

;------------------------------------------------------------------------------

MAIN_CONNECT:
	; **** Check Disconnection ****
	sbis	PIND, 3
	rjmp	MAIN_DISCONNECTING
	
	; **** Send EOP ****
	ldi		ZH, HIGH(DATA_EOP*2)
	ldi		ZL, LOW(DATA_EOP*2)
	ldi		arg1, 4
	rcall	USB_SND_ROM
	; **** Interval Count ****
	inc		icount
	cpi		icount, INTERVAL
	brne	MAIN_SEND_PROCESS
	ldi		icount, 0
	ldi		tmp1, 0x1F				; LED OFF
	out		PORTB, tmp1
	
	; **** Interrupt Transfer ****
	ldi		ZH, HIGH(DATA_PKT_DATA_IN_1_1*2)
	ldi		ZL, LOW(DATA_PKT_DATA_IN_1_1*2)
	ldi		arg1, 36
	rcall	USB_SND_ROM
	rcall	USB_RCV
	mov		tmp2, arg1
	ldi		ZH, HIGH(USBBUFSTART+8)	; Check DATA0/1 or NAK/STALL
	ldi		ZL, LOW(USBBUFSTART+8)
	ld		tmp1, Z
	sbrc	tmp1, 3
	rjmp	MAIN_LOOP
	ldi		ZH, HIGH(DATA_PKT_ACK*2)
	ldi		ZL, LOW(DATA_PKT_ACK*2)
	ldi		arg1, 20
	rcall	USB_SND_ROM
MAIN_PROCESS:
	; *** Processing Received Data ****
	mov		arg1, tmp2
	rcall	USB_CONV
	in		tmp1, PINB
	andi	tmp1, 0x02
	breq	MAIN_MOUSE_PROCESS
	rjmp	MAIN_KEY_PROCESS

MAIN_SEND_PROCESS:
	sbis	USR, 5
	rjmp	MAIN_LOOP
	rcall	GET_UART_BUF
	brcs	MAIN_SEND_PROCESS_END
	rcall	CONSOLE_PUT_CHAR
MAIN_SEND_PROCESS_END:
	rjmp	MAIN_LOOP

MAIN_KEY_PROCESS:
	ldi		keynum_n, 0
	ldi		YH, HIGH(USBBUFSTART+2)	; Y = USBBUFSTART+2
	ldi		YL, LOW(USBBUFSTART+2)
	ld		keysts, Y+
	ld		arg1, Y+
	or		arg1, arg1
	brne	MAIN_KEY_PROCESS_END
MAIN_KEY_PROCESS_1:
	ld		arg1, Y+
	or		arg1, arg1
	breq	MAIN_KEY_PROCESS_END
	ldi		tmp1, 0x1E				; LED ON
	out		PORTB, tmp1
	cp		keynum, reg_1
	brcc	MAIN_KEY_PROCESS_2
	rcall	SND_KEY_DATA
	ldi		keynum_n, 1
MAIN_KEY_PROCESS_2:
	ld		arg1, Y+
	or		arg1, arg1
	breq	MAIN_KEY_PROCESS_END
	cp		keynum, reg_2
	brcc	MAIN_KEY_PROCESS_3
	rcall	SND_KEY_DATA
	ldi		keynum_n, 2
MAIN_KEY_PROCESS_3:
	ld		arg1, Y
	or		arg1, arg1
	breq	MAIN_KEY_PROCESS_END
	cp		keynum, reg_3
	brcc	MAIN_KEY_PROCESS_END
	rcall	SND_KEY_DATA
	ldi		keynum_n, 3
MAIN_KEY_PROCESS_END:
	mov		keynum, keynum_n
	rjmp	MAIN_LOOP

MAIN_MOUSE_PROCESS:
	ldi		YH, HIGH(USBBUFSTART+2)	; Y = USBBUFSTART+2
	ldi		YL, LOW(USBBUFSTART+2)
	ld		arg1, Y+
	rcall	PUT_UART_BUF
	ld		arg1, Y+
	rcall	PUT_UART_BUF
	ld		arg1, Y
	rcall	PUT_UART_BUF
MAIN_MOUSE_PROCESS_END:
	rjmp	MAIN_LOOP

;------------------------------------------------------------------------------

MAIN_DISCONNECTING:
	; **** 500ms Wait ****
	ldi		tmp1, 0x1E			; LED ON
	out		PORTB, tmp1
	ldi		arg1, 5				; 500ms wait
	rcall	DELAY_100MS
	ldi		tmp1, 0x1F			; LED OFF
	out		PORTB, tmp1
	; **** Recheck Disconnection ****
	sbis	PIND, 3
	ldi		connect, 0			; Set State Disconnect
	rjmp	MAIN_LOOP

;------------------------------------------------------------------------------

MAIN_DISCONNECT:
	; **** Check Connection ****
	sbis	PIND, 3
	rjmp	MAIN_LOOP

;------------------------------------------------------------------------------

MAIN_CONNECTING:
	; **** 500ms Wait ****
	ldi		tmp1, 0x1E			; LED ON
	out		PORTB, tmp1
	ldi		arg1, 5				; 500ms wait
	rcall	DELAY_100MS
	ldi		tmp1, 0x1F			; LED OFF
	out		PORTB, tmp1
	; **** Recheck Connection ****
	sbis	PIND, 3
	rjmp	MAIN_LOOP
	ldi		tmp1, 0x1E			; LED ON
	out		PORTB, tmp1
	
	; **** USB Reset ****
	ldi		arg1, 200			; 200ms wait
	rcall	DELAY_1MS
	ldi		tmp1, 0x0C			; Set PD2 and PD3 as output mode
	out		DDRD, tmp1
	ldi		tmp1, 0x02			; Set Bus Reset
	out		PORTD, tmp1
	ldi		arg1, 10			; 10ms wait
	rcall	DELAY_1MS
	ldi		tmp1, 0x00			; Set PD2 and PD3 as input mode
	out		DDRD, tmp1
	ldi		tmp1, 0x00			; PD2-3 HI-Z
	out		PORTD, tmp1
	
	; **** 40ms Loop ****
	ldi		tmp1, 40
MAIN_CONNECTING_AFTER_RESET:
	push	tmp1
	ldi		arg1, 1				;1ms Wait
	rcall	DELAY_1MS
	; **** Send EOP ****
	ldi		ZH, HIGH(DATA_EOP*2)
	ldi		ZL, LOW(DATA_EOP*2)
	ldi		arg1, 4
	rcall	USB_SND_ROM
	pop		tmp1
	dec		tmp1
	brne	MAIN_CONNECTING_AFTER_RESET
	
	; **** Set Address ****
	ldi		ZH, HIGH(DATA_PKT_SETUP_TOKEN_0*2)
	ldi		ZL, LOW(DATA_PKT_SETUP_TOKEN_0*2)
	ldi		arg1, 36
	rcall	USB_SND_ROM
	ldi		ZH, HIGH(DATA_PKT_SET_ADDRESS_1*2)
	ldi		ZL, LOW(DATA_PKT_SET_ADDRESS_1*2)
	ldi		arg1, 100
	rcall	USB_SND_ROM
	rcall	USB_RCV
MAIN_CONNECTING_SET_ADDRESS:
	ldi		ZH, HIGH(DATA_PKT_DATA_IN_0_0*2)
	ldi		ZL, LOW(DATA_PKT_DATA_IN_0_0*2)
	ldi		arg1, 36
	rcall	USB_SND_ROM
	rcall	USB_RCV
	ldi		ZH, HIGH(USBBUFSTART+8)	; Check DATA0/1 or NAK/STALL
	ldi		ZL, LOW(USBBUFSTART+8)
	ld		tmp1, Z
	sbrc	tmp1, 3
	rjmp	MAIN_CONNECTING_SET_ADDRESS
	ldi		ZH, HIGH(DATA_PKT_ACK*2)
	ldi		ZL, LOW(DATA_PKT_ACK*2)
	ldi		arg1, 20
	rcall	USB_SND_ROM

	; **** Send EOP ****
	ldi		arg1, 1
	rcall	DELAY_1MS
	ldi		ZH, HIGH(DATA_EOP*2)
	ldi		ZL, LOW(DATA_EOP*2)
	ldi		arg1, 4
	rcall	USB_SND_ROM

	; **** Set Configuration ****
	ldi		ZH, HIGH(DATA_PKT_SETUP_TOKEN_1*2)
	ldi		ZL, LOW(DATA_PKT_SETUP_TOKEN_1*2)
	ldi		arg1, 36
	rcall	USB_SND_ROM
	ldi		ZH, HIGH(DATA_PKT_SET_CONFIGURATION_1*2)
	ldi		ZL, LOW(DATA_PKT_SET_CONFIGURATION_1*2)
	ldi		arg1, 100
	rcall	USB_SND_ROM
	rcall	USB_RCV
MAIN_CONNECTING_SET_CONFIG:
	ldi		ZH, HIGH(DATA_PKT_DATA_IN_1_0*2)
	ldi		ZL, LOW(DATA_PKT_DATA_IN_1_0*2)
	ldi		arg1, 36
	rcall	USB_SND_ROM
	rcall	USB_RCV
	ldi		ZH, HIGH(USBBUFSTART+8)	; Check DATA0/1 or NAK/STALL
	ldi		ZL, LOW(USBBUFSTART+8)
	ld		tmp1, Z
	sbrc	tmp1, 3
	rjmp	MAIN_CONNECTING_SET_CONFIG
	ldi		ZH, HIGH(DATA_PKT_ACK*2)
	ldi		ZL, LOW(DATA_PKT_ACK*2)
	ldi		arg1, 20
	rcall	USB_SND_ROM
	
	; **** Finish Connecting ****
	ldi		tmp1, 0x1F			; LED OFF
	out		PORTB, tmp1
	ldi		connect, 1			; Set State Connect

	rjmp	MAIN_LOOP

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------

; parameter	ZH:ZL ... send data address
;           arg1  ... send data length
; return	none
; crash		arg1, tmp1, ZH, ZL, r0

USB_SND_ROM:
	ldi		tmp1, 0x08			; 
	out		PORTD, tmp1
	ldi		tmp1, 0x0C			; Set PD2 and PD3 as output mode
	out		DDRD, tmp1
USB_SND_ROM_LOOP:
	lpm							; r0 = (Z)
	inc		ZL
	out		PORTD, r0
	dec		arg1
	brne	USB_SND_ROM_LOOP
USB_SND_ROM_LOOPEND:
	ldi		tmp1, 0x00			; Set PD2 and PD3 as input mode
	out		DDRD, tmp1
	out		PORTD, tmp1			; Set PD2 and PD3 as HI-Z
	ret

;------------------------------------------------------------------------------

; parameter	none
; return    arg1  ... received data length
; crash		arg1, tmp1, ZH, ZL

USB_RCV:
	ldi		ZH, HIGH(USBBUFSTART)	; Z = USBBUFSTART
	ldi		ZL, LOW(USBBUFSTART)
	ldi		tmp1, 100
USB_RCV_WAITLOOP:
	sbic	PIND, 3				; Wait until PD3(D-) == 0
	rjmp	USB_RCV_WAITLOOP
USB_RCV_RCVLOOP:
	in		arg1, PIND
	st		Z+, arg1
	andi	arg1, 0x0C
	breq	USB_RCV_ENDLOOP
	dec		tmp1
	brne	USB_RCV_RCVLOOP
USB_RCV_ENDLOOP:
	sbis	PIND, 3				; Wait until PD3(D-) == 1
	rjmp	USB_RCV_ENDLOOP
	ldi		arg1, 100
	sub		arg1, tmp1	
	ret

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------

; parameter	arg1  ... convert data length
; return	none
; crash		arg1, tmp1, tmp2. ZH, ZL

USB_CONV:
	rcall	USB_CONV_NRZI
	rcall	USB_CONV_BYTE
	ret

;------------------------------------------------------------------------------

; parameter	arg1  ... convert data length
; return	none
; crash		arg1, tmp1, tmp2, ZH, ZL

USB_CONV_NRZI:
	ldi		ZH, HIGH(USBBUFSTART)	; Z = USBBUFSTART
	ldi		ZL, LOW(USBBUFSTART)
	ldi		tmp1, 0x0B
USB_CONV_NRZI_LOOP:
	ld		tmp2, Z
	cp		tmp1, tmp2
	brne	USB_CONV_NRZI_NE
USB_CONV_NRZI_EQ:
	ldi		tmp2, 1
	rjmp	USB_CONV_NRZI_LOOPEND
USB_CONV_NRZI_NE:
	mov		tmp1, tmp2
	ldi		tmp2, 0
USB_CONV_NRZI_LOOPEND:
	st		Z+, tmp2
	dec		arg1
	brne	USB_CONV_NRZI_LOOP
	ldi		tmp1, 0xFF			; Set End Mark
	st		Z, tmp1
	ret

;------------------------------------------------------------------------------

; parameter	none
; return	none
; crash		arg1, arg2, tmp1, tmp2, YH, YL, ZH, ZL

USB_CONV_BYTE:
	ldi		YH, HIGH(USBBUFSTART)	; Y = USBBUFSTART
	ldi		YL, LOW(USBBUFSTART)
	ldi		ZH, HIGH(USBBUFSTART)	; Z = USBBUFSTART
	ldi		ZL, LOW(USBBUFSTART)
	ldi		tmp1, 0				; clear bit stuff count
USB_CONV_BYTE_LOOP1:
	ldi		tmp2, 0				; clear data
	ldi		arg1, 8
USB_CONV_BYTE_LOOP2:
	ld		arg2, Y+
	cpi		arg2, 0xFF
	breq	USB_CONV_BYTE_END
	ror		arg2
	ror		tmp2
	sbrs	tmp2, 7
	rjmp	USB_CONV_BYTE_0
USB_CONV_BYTE_1:
	inc		tmp1
	cpi		tmp1, 6
	brne	USB_CONV_BYTE_LOOPEND
	adiw	YL, 1
USB_CONV_BYTE_0:
	ldi		tmp1, 0
USB_CONV_BYTE_LOOPEND:
	dec		arg1
	brne	USB_CONV_BYTE_LOOP2
	st		Z+, tmp2
	rjmp	USB_CONV_BYTE_LOOP1
USB_CONV_BYTE_END:
	st		Z, arg2
	ret

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------

; parameter	arg1 ... value to convert
; return	arg1 ... converted char
;			carry .. 0:valid(0-15)  1:invalid(16-255)
; crash		arg1, tmp1

HEX_TO_CHAR:
	cpi		arg1, 16
	brcc	HEX_TO_CHAR_INVALID
	cpi		arg1, 10
	brcc	HEX_TO_CHAR_AF
HEX_TO_CHAR_09:
	ldi		tmp1, '0'
	add		arg1, tmp1
	clc
	ret
HEX_TO_CHAR_AF:
	ldi		tmp1, 'A'-10
	add		arg1, tmp1
	clc
	ret
HEX_TO_CHAR_INVALID:
	sec
	ret

;------------------------------------------------------------------------------

; parameter	arg1 ... char to put
; return	none
; crash		none

CONSOLE_PUT_CHAR:
	sbis	USR, 5
	rjmp	CONSOLE_PUT_CHAR
	out		UDR, arg1
	ret

;------------------------------------------------------------------------------

; parameter	arg1 ... value to put
; return	none
; crash		none

CONSOLE_PUT_HEX1:
	rcall	HEX_TO_CHAR
	rcall	CONSOLE_PUT_CHAR
	ret

;------------------------------------------------------------------------------

; parameter	arg1 ... value to put
; return	none
; crash		arg1

CONSOLE_PUT_HEX2:
	push	arg1
	swap	arg1
	andi	arg1, 0x0F
	rcall	CONSOLE_PUT_HEX1
	pop		arg1
	andi	arg1, 0x0F
	rcall	CONSOLE_PUT_HEX1
	ret

;------------------------------------------------------------------------------

; parameter	ZH:ZL ... value to put
; return	none
; crash		arg1

CONSOLE_PUT_HEX4:
	mov		arg1, ZH
	rcall	CONSOLE_PUT_HEX2
	mov		arg1, ZL
	rcall	CONSOLE_PUT_HEX2
	ret

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
	
TIM0_OVF:
	inc		tcount
	ldi		tmp1, 69			; 1ms Timer Count
	out		TCNT0, tmp1
	reti

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------

; parameter	arg1 ... delay time (ms)
; return	none
; crash		arg1, tmp1

DELAY_1MS:
	mov		tmp1, tcount
DELAY_1MS_LOOP:
	cp		tmp1, tcount
	breq	DELAY_1MS_LOOP
	dec		arg1
	brne	DELAY_1MS
	ret

;------------------------------------------------------------------------------

; parameter	arg1 ... delay time (100ms)
; return	none
; crash		arg1, tmp1, tmp2

DELAY_100MS:
	push	arg1
	ldi		arg1, 100
	rcall	DELAY_1MS
	pop		arg1
	dec		arg1
	brne	DELAY_100MS
	ret

;------------------------------------------------------------------------------

; parameter	arg1 ... value to buffer
; return	none
; crash		XH, XL

PUT_UART_BUF:
	ldi		XH, HIGH(UARTBUF)		; X = UARTBUF
	ldi		XL, LOW(UARTBUF)
	add		XL, uartwbuf
	st		X, arg1
	inc		uartwbuf
	cpi		uartwbuf, 6
	brne	PUT_UART_BUF_END
	ldi		uartwbuf, 0
PUT_UART_BUF_END:
	ret

;------------------------------------------------------------------------------

; parameter	none
; return	arg1 ... value from buffer
;			carry .. 0:valid value  1:buffer empty
; crash		arg1, XH, XL

GET_UART_BUF:
	cp		uartrbuf, uartwbuf
	breq	GET_UART_BUF_EMPTY
	ldi		XH, HIGH(UARTBUF)		; X = UARTBUF
	ldi		XL, LOW(UARTBUF)
	add		XL, uartrbuf
	ld		arg1, X
	inc		uartrbuf
	cpi		uartrbuf, 6
	brne	GET_UART_BUF_END
	ldi		uartrbuf, 0
GET_UART_BUF_END:
	clc
	ret
GET_UART_BUF_EMPTY:
	sec
	ret

;------------------------------------------------------------------------------

; parameter	arg1 ... value of key data
; return	zero ... 0:send  1:none
; crash		arg1, tmp1, ZH, ZL

SND_KEY_DATA:
	mov		tmp1, keysts
	andi	tmp1, 0x22
	brne	SND_KEY_DATA_SHIFT
SND_KEY_DATA_NORMAL:
	ldi		ZH, HIGH(DATA_USAGE_ID_TABLE*2)
	ldi		ZL, LOW(DATA_USAGE_ID_TABLE*2)
	rjmp	SND_KEY_DATA_CONV
SND_KEY_DATA_SHIFT:
	ldi		ZH, HIGH(DATA_USAGE_ID_TABLE_SHIFT*2)
	ldi		ZL, LOW(DATA_USAGE_ID_TABLE_SHIFT*2)
SND_KEY_DATA_CONV:
	add		ZL, arg1
	lpm
	mov		arg1, r0
	or		arg1, arg1
	breq	SND_KEY_DATA_END
	rcall	PUT_UART_BUF
	or		arg1, arg1
SND_KEY_DATA_END:
	ret

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
Detected encoding: UTF-80