Main.A51
; This module initializes the microcontroller then executes MAIN forever
;

Reset:
	MOV	SP, #235		; Initialize the Stack at top of internal memory
	MOV	PageReg, #7FH		; Needed to use MOVX @Ri

	MOV	R0, #LOW(USBControl)	; Simulate a disconnect
	MOVX	A, @R0
	ANL	A, #11110011b		; Clear DISCON, DISCOE
	MOVX	@R0, A
	CALL	Wait100msec   		; Give the host time to react
	MOVX	A, @R0			; Reconnect with this new identity
	ORL	A, #00000110b           ; Set DISCOE to enable pullup resistor
	MOVX	@R0, A	 		; Set RENUM so that 8051 handles USB requests
	CLR	A
	MOV	FLAGS, A		; Start in Default state
InitializeIOSystem:			; This example uses only I2C signals
					; No initialization is required
InitializeInterruptSystem:		; First initialize the USB level
	MOV	R0, #LOW(IN07IEN)
	MOVX	@R0, A			; Disable interrupts from IN Endpoints 0-7
	INC	R0
	MOVX	@R0, A			; Disable interrupts from OUT Endpoints 0-7
	INC	R0
	MOV	A, #00000011b
	MOVX	@R0, A			; Enable (Resume, Suspend,) SOF and SUDAV INTs
	INC	R0
	MOV	A, #00000001b
	MOVX	@R0, A	     		; Enable Auto Vectoring for USB interrupts
	MOV	R0, #LOW(OUT07IRQ)
	MOV	A, #0FFH
	MOVX	@R0, A			; Clear out any pending interrupts
	                                ; Now enable the main level
	MOV	EIE, #00000001b		; Enable INT2 = USB Interrupt (only) 		
        MOV	EI, #11000000b		; Enable interrupt subsystem (and Ser1 for Dscope)
 
; Initialization Complete.
; 
MAIN:
	NOP				; Not much of a main loop for this example
	JMP	MAIN			; All actions are initiated by interrupts
; We are a slave, we wait to be told what to do

Wait100msec:
	MOV	Temp, #100
Wait1msec:				; A delay loop
	MOV	DPTR, #-1200		
More:	INC	DPTR			; 3 cycles
	MOV	A, DPL                  ; + 2
	ORL	A, DPH                  ; + 2
	JNZ	More                    ; + 3 = 10 cycles x 1200 = 1msec
	DJNZ	Temp, Wait1msec
	RET

Wait4Stop:				; Make sure the STOP from a previous
	MOVX	A, @R0			; I2C transaction has completed
	JB	ACC.6, Wait4Stop
	RET
SendI2Caddress:				; Send the first byte to I2C bus
	CALL	Wait4Stop
	MOV	A, #10000000b		; Set the START bit
	MOVX	@R0, A			; I2C engine now primed
SendI2Cdatabyte:
	MOVX	A, @DPTR		; Get data and . . .
	MOVX	@R1, A			; . . . send using I2C engine
Wait4Done:
	MOVX	A, @R0
	JNB	ACC.0, Wait4Done	; Wait for the data to be transmitted
	RET

ProcessOutputReport:		  	; A Report has just been received
; The report is two bytes long
; Byte 1, Bits[7:1] = an I2C Address, Bit[0] = direction (0 = Write)
; Byte 2 = DataByte if byte 1 specifies a write
	MOV	R0, #LOW(I2CControl)	; Initialize the pointers to be used
	MOV	R1, #LOW(I2CData)
	MOV	DPTR, #EP0OutBuffer	; Point to the Report
	CALL	SendI2Caddress
	MOVX	A, @DPTR		; Retrieve Report Byte 1
	JB	ACC.0, I2C_Read
I2C_Write:
	INC	DPTR			; Point to data byte to write
	CALL	SendI2Cdatabyte
	MOV	A, #01000000b		; Set the STOP bit
	MOVX	@R0, A
	RET
I2C_Read:
	MOV	A, #00100000b		; Set the LASTRD bit
	MOVX	@R0, A
	MOVX	A, @R1			; Dummy read of I2C_Data
	CALL	Wait4Done
	MOV	A, #01000000b		; Set the STOP bit
	MOVX	@R0, A                  ; Immediately follow with . . .
	MOVX	A, @R1			; . . . read the I2C bus data
					; Fall into CreateInputReport
CreateInputReport:
; The report is only one byte long in this example
; It contains the byte read from the I2C bus 
	MOV	DPTR, #EP1InBuffer	; Point to the buffer 
	MOVX	@DPTR, A		; Update the Report
	MOV	DPTR, #IN1ByteCount
	MOV	A, #1
	MOVX	@DPTR, A		; Endpoint 1 now 'armed', next IN will get data
	RET