; 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