1620Timr.A51
; This module services the real time interrupt
; It is also responsible for the "real world" thermometers
;
; CHANGE SINCE THE BOOK TEXT WAS FINALIZED: Idle_Time is used by the Operating System
; to override the report times defined in the Endpoint Descriptor.  A device driver
; will modify Idle_Time to change the reporting characteristics of a HID device.
; During initialization the OS sets Idle_Time = 0 which turns reporting OFF unless
; a change is detected; an application that starts to poll a HID device will appear
; to hang. While it is possible to write extra PCHost application code to re-enable
; Idle_Time is it simpler to defeat this mechanism by IGNORRING the Idle_Time value.
;
; Get a Real Time interrupt every One millisecond (using SOF interrupt)
;
; We have one task = Read the thermometers
; We will poll the thermometers at 100msec intervals and store the temperatures
; directly in the EP1InBuffer. This way the PCHost will always get the latest
; temperature readings. 
;
; The hardware for this example is shown in Figure 9-7.
; We are using Port A for Output
; CLK is on Bit0, DQ is on Bit1 and the thermometers are selected by Bits[7:2]
;
; The registers used in this routine are:
;       A       = Value written to Port A
;       DPTR    = Pointer to EP1InBuffer
;       R0      = Pointer to PortA_Out
;       R1      = Pointer to PortA_Config then PortA_Pins
;       R2      = a save register
;       R5      = Data to be sent, or received
;       R6      = Thermometer selector
;       R7      = Bit counter
;
	CSEG
ServiceTimerRoutine:
	DJNZ    Msec_counter, Done      ; Only need to check every 100msec
	MOV     Msec_counter, #100      ; Reinitialize
;
	MOV     DPTR, #EP1InBuffer
	MOV     R0, #Low(PortA_Out)
	MOV     A, #00000100b           ; Select pattern
Loop:   MOV     R6, A
	MOV     A, #00000001b           ; Port A idle state
	ORL     A, R6
	MOVX    @R0, A                  ; Select one of the thermometers
	MOV     R5, #0AAH               ; Get temperature command
	CALL    SendByte
	CALL    ReceiveByte
	MOV     A, R6                   ; Get select pattern
	CLR     C                       ; Need to zero fill
	RLC     A                       ; Rotate pattern
	JNZ     Loop
; Check for ALARMs
	MOV	DPTR, #EP1InBuffer	; Current temperature values
	MOV	R0, #LimitValues	; Low limits
	MOV	R1, #LimitValues+6	; High limits
	MOV	R5, #0			; Alarm Value
	MOV	R6, #00000001b		; Alarm mask
	MOV	R7, #6			; Counter
LCLoop:	MOVX	A, @DPTR
	CLR	C
	SUBB	A, @R0			; Check low limit
	JNC	Over1
	MOV	A, R5			; Need to set this ALARM bit
	ORL	A, R6
	MOV	R5, A
Over1:	MOVX	A, @DPTR
	CLR	C
	SUBB	A, @R1			; Check upper limit
	JC	Over2
	MOV	A, R5			; Need to set this ALARM bit
	ORL	A, R6
	MOV	R5, A
Over2:	MOV	A, R6			; Rotate Alarm mask
	RL	A
	MOV	R6, A
	INC	DPTR			; Update pointers
	INC	R0
	INC	R1
	DJNZ	R7, LCLoop
	MOV	A, R5			; Get Alarm byte
	MOVX	@DPTR, A		; Store in Byte 7 of Report
	JMP	CreateInputReport	; RETurn via CreateInputReport

SendByte:                               ; Transmit a byte to a thermometer
	MOV     R7, #8
SLoop:  DEC     A
	MOVX    @R0, A                  ; Set CLK low
	XCH     A, R5                   ; Get the data to be sent
	RRC     A                       ; Put LS bit in Carry
	XCH     A, R5
	MOV     ACC.1, C                ; Put data bit in DQ
	MOVX    @R0, A
	INC     A
	MOVX    @R0, A                  ; Set CLK high
	DJNZ    R7, SLoop
	RET
ReceiveByte:                            ; Receive a byte from a thermometer
	MOV     R7, #9                  ; Actually we get 9 bits and discard bit0
	MOV     R2, A                   ; Save A while we reconfigure
	MOV     R1, #Low(PortA_OE)
	MOV     A, #11111101b
	MOVX    @R1, A                  ; Set bit 1 as input
	MOV     R1, #Low(PortA_Pins)
	MOV     A, R2                   ; Retreive A
GLoop:  DEC     A
	MOVX    @R0, A                  ; Set CLK low
	NOP				; Give thermomemter time to respond
	MOVX    A, @R1                  ; Read the data bit
	MOV     C, ACC.1                ; Copy DQ into Carry
	XCH     A, R5
	RRC     A                       ; Copy DQ into MSB
	XCH     A, R5
	INC     A
	MOVX    @R0, A                  ; Set CLK high
	DJNZ    R7, GLoop
	MOV     A, R5                   ; Get the received temperature
	MOVX    @DPTR, A		; Save in EPOInBuffer
	INC     DPTR
Done:   RET