;**********************************************************************
;   EDITED IN EDINBURGH 20 Sept 2002 (toggle improvement)             *
;   EDITED IN GENEVE on 29 sept 2002 (More scaling added)             *
;   EDITED IN VEIKKOLA   7 and 8 Oct 2002                             *
;   EDITED IN VEIKKOLA 23 Nov 2002 (no idle IR packets after power on)*
;   EDITED IN VEIKKOLA 24 Nov 2002 to refine autorepeat end           *
;                                                                     *
;   Full PC Remote Control System. The Remote Controller Software.    *
;                                                                     *
;   This ASM file is for a GKOS IR Remote Control code generation     *
;   on the PICmicro PIC16F876. Trackpoint mouse (IBM) is operated by  *
;   right thumb, cliking is done by left thumb and typing by six      *
;   fingers on the back of the device. For a full remote control for  *
;   for a PC, gkpcXX.asm is used at the PC mouse/kbd connector.       *
;                                                                     *
;             This source code can be used according to               *
;          The GNU GENERAL PUBLIC LICENSE Version 2, June 1991        *
;                                                                     *
;                 Seppo Tiainen, Veikkola, Finland                    *
;             See http://gkos.com for more on GKOS and                *
;                 http://gkos.net for schematics and details.         *
;                                                                     *
;                                                                     *
;   Refer to the MPASM User's Guide for additional information on     *
;   features of the assembler (Document DS33014).                     *
;                                                                     *
;   Refer to the respective PICmicro data sheet for additional        *
;   information on the instruction set.                               *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Filename:	gkir17.asm -> gkir17.hex                          *
;    Date:          13 Nov 2002                                       *
;    File Version:  1.6                                               *
;    Author:   Seppo Tiainen, Finland. Email: gkos@gkos.com           *
;    Company:  N/A                                                    *
;                                                                     * 
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files required:    p16f876.inc                                   *
;                                                                     *
;**********************************************************************


	list      p=16f876            ; list directive to define processor
	#include <p16f876.inc>        ; processor specific variable definitions

; It is necessary to use Crystal Oscilleator (XT_OSC, 4MHz) due to the accuracy required
; in generating the infrared transmission packets:

	__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _WRT_ENABLE_ON & _LVP_OFF & _CPD_OFF

; '__CONFIG' directive is used to embed configuration data within *.asm file.
; The lables following the directive are located in the respective *.inc file.
; See respective data sheet for additional information on configuration word.

;***** VARIABLE DEFINITIONS

w_temp       EQU     0x20        ; variable used for context saving 
status_temp  EQU     0x21        ; variable used for context saving
temp0        EQU     0x22
temp1        EQU     0x23
temp2        EQU     0x24

Flags		EQU	0x2F	;Flags: bit0=1 Mouse in use.
				;bit1=LButtonPrev, bit2=RButttonPrev, bit3=WButtonPrev
				;bit5=WButton (virtual), bit6=ToggleFlag, bit7=MToggleFlag
TDcounter	EQU	0x30
maxchord	EQU	0x31
finalchord	EQU	0x32
GKOSstatus	EQU	0x33	; bit0...
				; bit1=1: Typematic repeat is on.
				; bit2...
chord		EQU	0x34
dcount1		EQU	0x35
dcount2		EQU	0x36
dcount3		EQU	0x37
TEMPX		EQU	0x38	;temp byte to send
bitcounter	EQU	0x39	;bit counter
Yidle		EQU	0x3A	;Yin idle value (mouse not touched)
Xidle		EQU	0x3B	;Xin idle value	(mouse not touched)
Yin		EQU	0x3C	;Yin latest value
Xin		EQU	0x3D	;Xin latest value
Yabs		EQU	0x3E	;absolute values for curve table
Xabs		EQU	0x3F


;This procedure is repeated continuously:

;scan keys first time > wait 5ms > If needed send Mouse report > wait 5ms >
;scan keys second time > send Chord value packet > repeat

;---this does not necessarily take care of simultaneous typing and mouse operation!

;---Format of Chord value packet:
;[start] D0 D1 D2 D3 D4 D5 G  1  A0 A1 A2

;---Format of Mouse data packets:
;[start] D0 D1 D2 D3 D4 D5  G  0  A0 A1 A2 A3 Z(=0) 
;X0 X1 X2 X3 X4 X5 X6 X7  Y0 Y2 Y3 Y4 Y5 Y6 Y7  (pointer movement data)

;[start] D0 D1 D2 D3 D4 D5  G  0  A0 A1 A2 A3 Z(=1) 
;Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7			(scroll wheel data)

;Mouse bytes to send (bit0 to be sent first):
MouseByte1	EQU	0x40	; 0  G  D5 D4 D3 D2 D1 D0
				;0(mouse) MToggle Yovl Xovl Ysign Xsign RButton LButton
MouseByte2	EQU	0x41	;- - - Z A3 A2 A1 A0  (A0-A2 = device address)
				;(only 5 bits to be sent, A3=0, Z=1 for scroll wheel data)
MouseByte3	EQU	0x42	;X7 X6 X5 X4 X3 X2 X1 X0 (X movement data)
MouseByte4	EQU	0x43	;Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 (Y movement data)
MouseByte3W	EQU	0x44	;Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0 (Scroll wheel data)

maxMcounter	EQU	0x4E	;counter for max number of 'no mouse buttons pressed' transmissions 
maxcounter	EQU	0x4F	;counter for max number of zero chord transmissions 
IRdevice	EQU	0x50	;Present device information of the IR packet:
				;xxxaaadg  x x x A2   A1 A1 D7(1) D6(G)
;**************
TEMP		EQU	0x51	; Temp localregister

;Definitions

	; Scaling.  RIPPLE was added AFTER testing version v1.2
	#define RIPPLE		d'10'	; The amount of force to start send first mouse data

	; Added after version 12 to the new version: gkir14.asm
	; More Scaling. To slow down movement with small values of Xabs/Yabs:
	;                 Step1   Step2 Step3
	;                 v       v     v 
	; 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14...
	; 1 1 1 1 1 1 1 1 2 2 2 2 3 3 3  4  5  6  7  8 
	#define	Step1	0x09	; Mouse Xabs and Yabs Scaling Steps
	#define	Step2	0x0d	; 0...Step1-1 gives 1, Step1...Step2-1 gives 2
	#define	Step3	0x10	; Step2...Step3-1 gives 3 and Step3 up is 4,5,6,7,8,...

	#define	LButtonIn	PORTB,7
	#define	RButtonIn	PORTB,6

	#define	LButton		MouseByte1,0
	#define	RButton		MouseByte1,1
	#define 	Xsign		MouseByte1,2
	#define	Ysign		MouseByte1,3
	#define 	Xovl		MouseByte1,4
	#define	Yovl		MouseByte1,5
	#define	MToggle		MouseByte1,6

	#define	MOUSEINUSE	Flags,0	;Mouse in use (bias found)
	#define LButtonPrev	Flags,1 ;Previous state of Left  Mouse button
	#define RButtonPrev	Flags,2 ;Previous state of Right Mouse button
	#define WButtonPrev	Flags,3 ;Previous state of Wheel Mouse button
	;...
	#define WButton		Flags,5 ;State of Wheel Mouse button (virtual button)
	#define ToggleFlag	Flags,6	;Need to change Toggle bit for next non zero key data
	#define MToggleFlag	Flags,7	;Need to change MToggle bit for next non zero button data
	#define	AUTOCOUNT	d'60'	;Typematic delay. Autorepeat wait time.
	#define	TYPEMATIC	GKOSstatus,1 ; Typematic on flag
	#define	IRTXDATA	PORTC,0
	#define MDEVICE		b'00000111' ;A2-A0 = 111
;				  ---00aaa(- - - Z A3 A2 A1 A0) Z A3 = 00 (pointer data)
	#define DEVICE		b'00011110' ;A2-A0 = 111,  dg = 1 G
;				  xxxaaadg            gdaaa     gdaaa-
;				b'00011110' => scope: 01111, ...011110 (=MD) gdaaa0
;	SIRC spec: 00010 = Betamax (5-bit code); 01111 = MD (5-bit code)	
;	TESTED: b'00011110' on scope: 01111; MD on scope: 11110 =>
;	b'00011110'	;Send the default IR device code in reverse order (LSB first).
;GKOS:	D0 D1 D2 D3 D4 D5    D6 D7 A0 A1 A2
;SIRC:	D0 D1 D2 D3 D4 D5    D6 A0 A1 A2 A3 A4
;GKOS:	D0-D5=chord, D6=toggle(g), D7=1(d), A0-A2=address (now: aaa=111)
;SIRC:	D0-D6=data, A0-A4=address (MD: 11110)
;	Examples:
;	dddddd gdaaa
;GKOS:	010000 01111	'a'
;SIRC:	0100000 11110 	'3'
;	ddddddd aaaaa
;****** Macros ********************************************************

Delay   macro   Time            ;Delay "Cycles" instruction cycles 
    if (Time==1) 
          nop 
          exitm 
    endif 
    if (Time==2) 
          goto $ + 1 
          exitm 
    endif 
    if (Time==3) 
          nop 
          goto $ + 1 
          exitm 
    endif 
    if (Time==4) 
          goto $ + 1 
          goto $ + 1 
          exitm 
    endif 
    if (Time==5)  
          goto $ + 1 
          goto $ + 1 
          nop 
          exitm 
    endif 
    if (Time==6) 
          goto $ + 1 
          goto $ + 1 
          goto $ + 1 
          exitm 
    endif 
    if (Time==7) 
          goto $ + 1 
          goto $ + 1 
          goto $ + 1 
          nop 
          exitm 
    endif 
    if (Time%4==0) 
          movlw (Time-4)/4 
          call Delay_Routine 
          exitm 
    endif 
    if (Time%4==1) 
          movlw (Time-5)/4 
          call Delay_Routine 
          nop 
          exitm 
    endif 
    if (Time%4==2) 
          movlw (Time-6)/4 
          call Delay_Routine 
          goto $ + 1 
          exitm 
    endif 
    if (Time%4==3) 
          movlw (Time-7)/4 
          call Delay_Routine 
          goto $ + 1 
          nop 
          exitm 
    endif 
    endm 

;**********************************************************************

	ORG     0x000       	; processor reset vector
	clrf    PCLATH          ; ensure page bits are cleared
  	goto    main            ; go to beginning of program

main

	bsf	STATUS,RP0      ; change to register bank 1
	bcf	STATUS,RP1	;           ===============

	movlw	b'00011111'	; (A/D) binary value, 1 bit per port bit
	movwf	TRISA		; RA0....RA4 set to inputs for A/D converter,


				; Port B - GKOS keys plus Left and Right Mouse Buttons
	movlw	b'11111111'	; binary value, 1 bit per port bit
	movwf	TRISB		; RB0-RB7 set to digital inputs,
				; RB0-RB5 GKOS Keyboard
				; RB6     Right button input
				; RB7     Left  button input


	movlw	b'11111100'	; binary value, 1 bit per port bit
	movwf	TRISC		; RC0 set to digital output IRTXDATA,
				; RC1 set to PWM output to calibrate TrackPoint mouse bias
				; ...all other PORTC pins are inputs

	bcf	OPTION_REG,7	;...for bank 1 OPTION_REG: clear bit 7 for pull-ups
				; on port B (GKOS keys)

;A/D Converter configure--->
	;ADCON1 Register: - - ADFM - PCFG3 PCFG2 PCFG1 PCFG0 (Port Configure)
	movlw	b'00000100'	;ADRESH/L are left justified (..0.....) as described below
	movwf	ADCON1		;AN0, AN1 and AN3 are configured as Analog Inputs (....0100)
				;RA2 and RA4 are digital inputs
;<---A/D

;PWM settings for default mouse bias--->

	movlw	0x3F		;Set PWM Period at pin 12 (RC1)
	movwf	PR2		;4 MHz Clock Frequency gives then 15.624 kHz
				;(if TMR2 Prescaler = 1 as below)

	bcf	STATUS,RP0	; change to register bank 0
				;           ===============

				;PWM DUTY CYCLE.  CCPR2L: DC2B9...DC2B2
				;Bits 5 and 4 of CCP2CON: DC2B1...DC2B0 (Duty Cycle LSBs)
	movlw	0x1E	;0x1E  Set 50% PWM Duty Cycle at pin 12 (RC1) (bits 9...2)
	movwf	CCPR2L		;DC2B9...DC2B0:       0010000000 (80h) 50%
				;DC2B9...DC2B2:       00100000   (20h) 50%
				;PWM Period in PR2:   00111111   (3Fh)
	;PWM Duty cycle is now selectable between 0...0x3F (0...100%) in register CCPR2L
	;Finetune duty cycle by bits 5 and 4 in CCP2CON
				;For PWM mode activation and default Duty Cyle fine tune:
				;Control Register CCP2CON: 0 0 DC2B1 DC2B0 1 1 x x
	movlw	b'00001100'	;Clear Duty Cycle LSBs and select PWM operation (....11..)
	movwf	CCP2CON
				;Write to Register T2CON to set TMR2 (Timer2) prescale value
				;and to enable Timer2. (TOUTPS3..1 are for postscaler)
				; - TOUTPS3 TOUTPS2 TOUTPS1 TOUTPS0 TMR2ON T2CKPS1 T2CKPS0
	movlw	b'00000100'	;TMR2 Prescaler = 1 (bits are then ......00)
	movwf	T2CON		;Timer2 is turned ON: .....1..
				
;<---PWM

;A/D Converter of 10 bits--->

	;ADCON0 Register: ADCS1 ADCS0 CHS2 CHS1 CHS0 GO/done Resv ADON
	movlw	b'00000001'	;Bit 0 of ADCON0 register => 1 to turn A/D operation on.
	movwf	ADCON0		;CHS2 CHS1 CHS0: Select channel 000=AN0 (RA0), 001=AN1 (RA1) 
	; A/D input is now readable by setting bit 2 of ADCON0 (GO) and polling the same
	; bit until it is 0. The Result is then in ADRES (A/D result) register (ADRESH and
	; ADRESL: xxxxxxxx and xx000000)
				
;<---A/D converter

	movlw	DEVICE		;Initialize IR device id
	movwf	IRdevice

	movlw	d'1' ;d'32'
	movwf	maxcounter	;Initialize zero-chord max send counter
	movlw	d'1' ;d'32'
	movwf	maxMcounter	;Initialize 'no mouse buttons pressed' max send counter
	;these counters must be set to d'1' to disable initial transmission of
	; 32 idle mouse and chord packets at power on after mouse bias, else d'32'

	call	SetMouseBias	;Initialize TrackPoint mouse bias voltage
				; to provide 1.8V at Yin when mouse is idle

	clrf	MouseByte1	;Clear parameter 0  G  D5 D4 D3 D2 D1 D0
	movlw	MDEVICE
	movwf	MouseByte2	;Init. parameter - - - Z A3 A2 A1 A0 (A0-A2=device address)
	clrf	MouseByte3	;Clear parameter       ^Z=0 pointer / Z=1 wheel data
	clrf	MouseByte4	;Clear parameter
	clrf	MouseByte3W	;Clear parameter

	bcf	LButtonPrev	;Set defaults
	bcf	RButtonPrev
	bcf	ToggleFlag
	bcf	MToggleFlag
;****************************************************************************
GKOSloop
				;Check GKOS keyboard
;	call	CheckMouse

;	;call	ReadGKOSchord   ;return when keys released with param. finalchord	
;	;btfss	GKOSstatus,0	;was there any key pressed? bit0 = 1?
;	;goto	GKOSloop	;no, check again
;	;goto	ChordReceived	;Yes!

;---NON-ZERO CHORDS:---------------------------------------------------
ScanKeys

	;Scan keys twice before sending

	call	OneScan		;Scan Keyboard FIRST TIME

				;Continue scanning GKOS keyboard

	movlw	d'5'		;DELAY 5ms
	call	DelayWx1ms	

	call	CheckMouse	;Check mouse and send report if needed

	movlw	d'5'		;DELAY 5ms
	call	DelayWx1ms	

	movlw	0x00		;Is chord zero (no GKOS keys down at the moment)
	xorwf	chord,W		;...
	btfsc	STATUS,Z	;...i.e. chord Equal to 0? 
	goto	ScanKeys0	;Yes. Prepare for changing Toggle bit.
				;No.

	movlw	d'32'		;Chord non-zero =>
	movwf	maxcounter	;Initialize zero-chord max send counter


	call	OneScan		;Scan Keyboard SECOND TIME

			;CHECK THIS:
	;movlw	0x00		;Is it zero (no GKOS keys down at the moment)
	;xorwf	chord,W		;...
	;btfsc	STATUS,Z	;...i.e. chord Equal to 0? 
	;goto	ScanKeys0	;Yes. Prepare for changing Toggle bit.
				;No.


ScanKeys_1

	btfss	TYPEMATIC	;Typematic on? Autorepeat?
	goto	ScanKeys_11	;No.
				;Yes. Toggle D6(G)
	movlw	b'00000001'	;xxxa aadg
	xorwf	IRdevice,F	;toggle MSB

ScanKeys_11
;------------new code:

	; If chord <> finalchord, then TDcounter must be initialized so that Autorepeat
	; will not happen when chords are changed while being pressed continuously.<<<<<<<

	movf	maxchord,W
	xorwf	finalchord,W	; new maxchord = previous finalchord?
	bz	ScanKeys_12	; Yes. Just go on.
				; No. Chord has changed. Initialize Autorepeat downcounter.
	movlw	AUTOCOUNT	; Initialize Autorepeat down-counter
	movwf	TDcounter	; when chord changes (or no keys are pressed)

	; Fool the toggle function so that this different character will not be received.
	; now the toggle bit change later will give the same value as the last repeated char.
	btfss	TYPEMATIC	; Is Typematic (autorepeat) on?
	goto	ScanKeys_12	; No.
	movlw	b'00000001'	; Yes. xxxa aadg
	xorwf	IRdevice,F	;toggle MSB
	bcf	TYPEMATIC	;reset outorepeat indication

	movlw	d'20'		; Extra delay to wait when autorepeat has stopped.
	call	DelayWx10ms	; Wait 200 ms and send nothing
	clrf	maxchord
	clrf	finalchord
	goto	GKOSloop

ScanKeys_12
;--------------end of new code

	movf	maxchord,W	;Just send the present maxchord (of two scans) value
	movwf	finalchord

	;IR packet takes about 18 ms to send
	call	SendStart	;2200us pulse
	call	SendChord	;6 bits
	call	SendDevice	;5 bits (00010 = Betamax)

	clrf	maxchord	;clear maxchord

	goto GKOSloop


;----- ZERO CHORDS:---------------------------------------------------
ScanKeys0

	movlw	AUTOCOUNT	;Initialize Autorepeat down-counter
	movwf	TDcounter	;when no keys are pressed
	bcf	TYPEMATIC	;reset autorepeat indication

	movlw	d'0'
	movwf	maxchord

	call	OneScan		;Scan keyboard FIRST TIME

	movlw	d'5'		;DELAY 5ms
	call	DelayWx1ms	

	call	CheckMouse	;Check Mouse and send report if needed

	movlw	d'5'		;DELAY 5ms
	call	DelayWx1ms	

	movlw	0x00		;Is chord zero (no GKOS keys down at the moment)
	xorwf	chord,W		;...
	btfsc	STATUS,Z	;...i.e. chord Equal to 0? 
	goto	ScanKeys02	;Yes. Scan second time.
				;No. Toggle D6(G) and Send next chord <> 0
	movlw	b'00000001'	;xxxa aadg
	xorwf	IRdevice,F	;toggle MSB

	movlw	d'32'
	movwf	maxcounter	;Initialize zero-chord max send counter

	goto	ScanKeys	;Continue by sending non-zero chords

ScanKeys02
	call	OneScan		;Scan keyboard SECOND TIME

	movlw	0x00		;Is it zero (no keys down at the moment)
	xorwf	chord,W		;...
	btfsc	STATUS,Z	;...i.e. chord Equal to 0? 
	goto	ScanKeys0_1	;Yes. SEND but maximum 32 times.
				;No. Toggle D6(G) and Send next chord <> 0
	movlw	b'00000001'	;xxxa aadg
	xorwf	IRdevice,F	;toggle MSB

	movlw	d'32'
	movwf	maxcounter	;Initialize zero-chord max send counter

	goto	ScanKeys	;Continue by sending non-zero chords

ScanKeys0_1
	decfsz	maxcounter,f	;Max number of zero-chords sent?
	goto	ScanKeys_02	;No.
	incf	maxcounter,f	;Yes. Prepare for next check.
				;Do not send.
	goto	ScanKeys0	;
	
ScanKeys_02
	movf	chord,W		;Send the present chord value = 0 
	movwf	finalchord

	;IR packet takes about 18 ms to send

	call	SendStart	;2200us pulse
	call	SendChord	;6 bits
	call	SendDevice	;5 bits

	goto	ScanKeys0

;-----------subs:----------------------------------------------------
OneScan
	decfsz	TDcounter,f	;Decrement Autorepeat down counter.
	goto	OneScan_1
	incf	TDcounter,f	;Increment by one to end up here next time too.
	bsf	TYPEMATIC	;indicate Typematic on
OneScan_1
	movf	PORTB,W		;Read GKOS Chord into param. chord
	xorlw	0xFF		;invert bits (pull-up function)
	andlw	b'00111111'	;clear RB7 & RB6 positions	
	movwf	chord		;store chord pressed at the moment

OneScan_2
	movf	chord,W		; Save again in W too
	iorwf	maxchord,F	;add any new bits (keys)
	return			;Chord in 'chord' and W

;******************
SendChord
	movf	finalchord,w
	movwf	TEMPX		;TEMPX = byte to send (6 bits only, bit0 first)
	movlw	d'6'
	movwf	bitcounter	;set counter for 6 bits
SendChord_a
	btfss	TEMPX,0		;bit0=1?
	goto	SendChord_0	;No

	call	Send_1		;Yes SEND '1'
	rrf	TEMPX,f		;Next bit
	decfsz	bitcounter,f	;All 6 bits sent?
	goto	SendChord_a	;No.
	return			;yes, return
SendChord_0
	call	Send_0		;SEND '0'
	rrf	TEMPX,f		;Next bit
	decfsz	bitcounter,f	;All 6 bits sent?
	goto	SendChord_a	;No.
	return			;Yes, return
;*******************
SendDevice			;Send Device information (the IR controlled device ID)
	;movlw	DEVICE
	movf	IRdevice,W	;
	movwf	TEMPX
	movlw	d'5'
	movwf	bitcounter	;set counter for 5 bits
SendDevice_a
	btfss	TEMPX,0		;bit0=1?
	goto	SendDevice_0	;No

	call	Send_1		;Yes
	rrf	TEMPX,f		;Next bit
	decfsz	bitcounter,f	;All 5 bits sent?
	goto	SendDevice_a	;No.
	return			;yes, return
SendDevice_0
	call	Send_0
	rrf	TEMPX,f		;Next bit
	decfsz	bitcounter,f	;All 5 bits sent?
	goto	SendDevice_a	;No.
	return			;Yes, return



;------------------MOUSE FUNCTIONS-------------------------------
SendMByte1
;MouseByte1: 0  G  D5 D4 D3 D2 D1 D0
;0(mouse) Toggle Yovl Xovl Ysign Xsign RButton LButton
	movf	MouseByte1,w
	movwf	TEMPX		;TEMPX = byte to send (8 bits, bit0 first!)
	movlw	d'8'
	movwf	bitcounter	;set counter for 8 bits
	goto 	SendMByte_a
;----
SendMByte2
;- - - Z A3 A2 A1 A0 
;(only 5 bits to be sent, A3=0, Z=1 for wheel data)
	movf	MouseByte2,w
	movwf	TEMPX		;TEMPX = byte to send (5 bits, bit0 first!)
	movlw	d'5'
	movwf	bitcounter	;set counter for 5 bits
	goto 	SendMByte_a
;----
SendMByte3
;MouseByte3:  X7 X6 X5 X4 X3 X2 X1 X0 (X movement data)
	movf	MouseByte3,w
	movwf	TEMPX		;TEMPX = byte to send (8 bits, bit0 first!)
	movlw	d'8'
	movwf	bitcounter	;set counter for 8 bits
	goto 	SendMByte_a
;---
SendMByte4
;MouseByte4:  Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 (Y movement data)
	movf	MouseByte4,w
	movwf	TEMPX		;TEMPX = byte to send (8 bits, bit0 first!)
	movlw	d'8'
	movwf	bitcounter	;set counter for 8 bits
	goto 	SendMByte_a
;---
SendMByte3W
;MouseByte3W: Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0 (Scroll wheel data)
	movf	MouseByte3W,w
	movwf	TEMPX		;TEMPX = byte to send (8 bits, bit0 first!)
	movlw	d'8'
	movwf	bitcounter	;set counter for 8 bits
	goto 	SendMByte_a

;-------common part:
SendMByte_a
	btfss	TEMPX,0		;bit0=1?
	goto	SendMByte_0	;No

	call	Send_1		;Yes SEND '1'***
	rrf	TEMPX,f		;Next bit
	decfsz	bitcounter,f	;All 8 bits sent?
	goto	SendMByte_a	;No.
	return			;yes, return
SendMByte_0
	call	Send_0		;    SEND '0'***
	rrf	TEMPX,f		;Next bit
	decfsz	bitcounter,f	;All 8 bits sent?
	goto	SendMByte_a	;No.
	return			;Yes, return

;===========================================

;---NOT USED:
LOOP
	btfsc	PORTC,1		; test status of PORTC bit 1
	bsf     PORTC,0		; if high, set PORTC bit 0, turn on LED
	call	onesec		; call one second delay routine
	bcf     PORTC,0		; clear PORTC bit 0, turn off LED
	call	onesec		; call one second delay routine
	goto	LOOP		; loop infinitely turning LED on and off
onesec				; one second delay subroutine

	movlw	d'100'		; decimal value one hundred
	movwf	temp0		; load value d'100 into variable temp0
	movlw	d'13'	
	movwf	temp1		; load value d'13 into variable temp1
	movlw	d'250'	
	movwf	temp2		; load value d'250 into variable temp2
onesec_a
	decfsz	temp2,F		; decrement temp2 by 1, result in temp2
	goto	onesec_a	; innermost loop
	decfsz	temp1,F		; decrement temp1 by 1, result in temp1
	goto	onesec_a	; middle loop
	decfsz	temp0,F		; decrement temp0 by 1, result in temp0
	goto	onesec_a	; outer loop
	return			; return from subroutine
;******************************************************************

SendPointerData
	call	SendStart	;2200us pulse
	call	SendMByte1	;8 bits (buttons, signs, overflow, Toggle)
	call	SendMByte2	;5 bits (A0-A3,Z=0;  00010 = Betamax)
	call	SendMByte3	;8 bits (X movement)
	call	SendMByte4	;8 bits	(Y movement)
	;call	SendMPause	;pause between mouse packets
	return
;-----------------------



SendWheelData
	call	SendStart	;2200us pulse
	call	SendMByte1	;8 bits (buttons, signs, overflow, Toggle)
	bsf	MouseByte2,4	;Set Z=1 to indicate scroll wheel data
	call	SendMByte2	;5 bits (A0-A3,Z=1;  00010 = Betamax)
	bcf	MouseByte2,4	;Back to default: Z=0 indicates pointer movement data
	call	SendMByte3W	;8 bits (Z movement, scroll wheel)
	;call	SendMPause	;pause between mouse packets
	return


;*********************-COMMON SUBROUTINES-**********************************************
DelayWx10ms
	movwf	dcount1 	; dcount1 = W
	movlw	0x64
	movwf	dcount2 
	movlw	0x20
	movwf	dcount3 
	decfsz	dcount3,F	; delay of > ((((3 * dcount3)+3)*dcount2)+3*W)
	goto 	$ - 1		;    * instruction cycle time (1us for 4MHz)
	decfsz	dcount2,F
	goto 	$ - 5		; so currently W x 10ms
	decfsz	dcount1,F
	goto 	$ - 9		

	return

;*********************
;Delays 4w+4 cycles (including call,return, and movlw) (0=256) 
Delay_Routine   addlw   -1              ;Precise delays used in I/O 
                btfss   STATUS, Z  
                goto    Delay_Routine 
                return     
;*********************
DelayWx1ms
	movwf	dcount1 	; dcount1 = W
	movlw	0x0a
	movwf	dcount2 
	movlw	0x20
	movwf	dcount3 
	decfsz	dcount3,F	; delay of > ((((3 * dcount3)+3)*dcount2)+3*W)
	goto 	$ - 1		;    * instruction cycle time (1us for 4MHz)
	decfsz	dcount2,F
	goto 	$ - 5		; so currently W x 1ms
	decfsz	dcount1,F
	goto 	$ - 9		

	return
;*******************************************************************
DelayT			;IR pulse Basic time period T = 550us
	Delay	d'200'
	Delay	d'200'
	Delay	d'150';<150
	return
DelayTplus		;IR pulse data bit check period = 825us
	Delay	d'200'
	Delay	d'200'
	Delay	d'200'
	Delay	d'200'
	Delay	d'25'
	return
;****************************************************************
SendPause		;Pause between chord packets = 24ms
	bcf	IRTXDATA
	movlw	d'24'
	call	DelayWx1ms
	return
;------
SendMPause		;Pause between mouse packets = 10ms
	bcf	IRTXDATA
	movlw	d'10'
	call	DelayWx1ms
	return
;****************************************************************
SendStart		;gap T (550us), pulse 4T (2200us) 
	bcf	IRTXDATA
	call	DelayT
			;19 cycles per T -> 35.7kHz (19.5 => 36kHz)
			;One cycle: 14us high + 14us low
	movlw	d'78'	;**<78<=Oscilloscope** ;set cycle counter to 4T = 4 x 19.5 = 78
	movwf	temp0	;78 x 28us = 2184 (16us missing) 
	goto	SendPulse
;-----------
Send_1			;gap T (550us), pulse 2T (1100us)
	bcf	IRTXDATA
	call	DelayT
			;19 cycles per T -> 35.7kHz
			;One cycle: 14us high + 14us low
	movlw	d'43';**<43<=Oscilloscope**	;set cycle counter to 2T = 2 x 19 = 38
	movwf	temp0	;38 x 28us = 1064us (36us missing)
	goto	SendPulse
;----------------------
Send_0			;gap T (550us), pulse T (550us)
	bcf	IRTXDATA
	call	DelayT
			;19 cycles per T -> 35.7kHz
			;One cycle: 14us high + 14us low 
	Delay	d'10'	;the missing 18us - 8us for program lines calling
	movlw	d'22';**<22<=Oscilloscope**  ;set cycle counter to T = 1 x 19 = 19
	movwf	temp0	;19 x 28us = 532us (18us missing)
	goto	SendPulse
;-----------------------
	;This sets the Carrier Frequency! Adjusted by Oscilloscope. Do not change!
SendPulse	;Common procedure to send n cycles (n = temp0)
	bsf	IRTXDATA	;1
	Delay	0x0d; **0x0d>14us<=Oscilloscope** 13 ;1+13 = 14us
	bcf	IRTXDATA	;1
	Delay	0x0a; **0x0a>14us<=Oscilloscope** ;>14us;  ;1+11
	decfsz	temp0,f		;1+1+11
	goto	SendPulse	;1+1+1+11 = 14us
	return


;***********************-TRACKPOINT SETUP FUNCTIONS-***************************************
SetMouseBias
	;PWM Duty cycle is selectable between 0...0x3F (0...100%) in register CCPR2L
	;(Finetune duty cycle by bits 5 and 4 in CCP2CON, not used in this version)
	;Control Register CCP2CON: 0 0 DC2B1 DC2B0 1 1 x x

	;Set Finetune to maximum value (just a fixed value for finetune)
	movlw	b'00111100'	;Set Duty Cycle LSBs (..11....)
	movwf	CCP2CON

	;Set duty cycle MSBs to zero
	movlw	b'00000000'
	movwf	CCPR2L

SMBLoop
	;Test Yin voltage
	; A/D input is readable by setting bit 2 of ADCON0 (GO) and polling the same
	; bit until it is 0. The Result is then in ADRES (A/D result) register (ADRESH and
	; ADRESL: xxxxxxxx and xx000000) Note that register ADRESL is in Bank 1 !!!
	; ADCON0 Register: ADCS1 ADCS0 CHS2 CHS1 CHS0 GO/done Resv ADON
	;
	; X & Y pin voltage:    0V ... 2V ... 5V
	; Duty Cycle values:   0x00...0x1f...0x3f
	; A/D voltage values:  0x00...0x5f...0xff(?) 
	; 0x00=0V ... 0x5F=2V ... 
	;  => 2V (0x5f) is the target bias at Yin (= RA0/AN0)
ADLoop0
	movlw	d'10'		;Delay of 10ms for duty cycle change to have an impact.
	call	DelayWx1ms
	;Delay	d'10'		;Aquisition time 10us
	bsf	ADCON0,2	;Set GO to start A/D conversion
ADLoop
	btfsc	ADCON0,2	;A/D coversion Ready?
	goto	ADLoop		;No. Go back.
				;Yes. Done.

	;Test if voltage has reached 2V = ca. 0x5F (= A/D analog input value)

	movf	ADRESH,W	;Test if result higher than 0x5F (2V)
	sublw	0x5F		; 0x5F - W
	btfss	STATUS,C	;Note: C = complement of Borrow
	goto	ADLoopX		;Yes, higher. Go on and finetune bias.
				;No. Increase Duty Cycle = increase bias

	;PWM Duty cycle is selectable between 0...0x3F (0...100%) in register CCPR2L

	incf	CCPR2L,f	;Increase voltage. Next Duty Cycle value.
	movf	CCPR2L,W	;0x40 reached? (100% duty cycle?)
	xorlw	0x40		;=0x40?
	bnz	ADLoop0		;Not equal. Test if bias found with this new value.
				;Yes, equal.
	bcf	MOUSEINUSE	;Mouse cannot be used because...
	return			; 100% Duty cycle was reached. Error return.
				; No bias found or no mouse connected.
				; X and Y input pins must be grounded if no mouse!
ADLoopX


;----add finetune here if needed----

	bsf	MOUSEINUSE	;Indicate that Mouse can be used.

	;*****Store Yin and Xin idle values (mouse not touched)

	movlw	d'10'		;wait 100 ms to allow D/A capacitor to settle to idle value
	call	DelayWx10ms	;Delay

	;First	AN0/RA1 input
	
	Delay	d'50'		;Aquisition time 50us
	bsf	ADCON0,2	;Set GO to start A/D conversion
YStoreLoop
	btfsc	ADCON0,2	;A/D coversion Ready?
	goto	YStoreLoop	;No. Go back.
				;Yes. Done.
	movf	ADRESH,W	;
	movwf	Yidle		;*** Store Yin idle value (A/D).

	;Select then AN1/RA1 input
	bsf	ADCON0,3

	Delay	d'50'		;Aquisition time 50us
	bsf	ADCON0,2	;Set GO to start A/D conversion
XStoreLoop
	btfsc	ADCON0,2	;A/D coversion Ready?
	goto	XStoreLoop	;No. Go back.
				;Yes. Done.
	movf	ADRESH,W	;
	movwf	Xidle		;*** Store Xin idle value (A/D).

	bcf	ADCON0,3	;Switch back to AN0/RA0 input.
	return
;******************************************************************************
ReadXY
	;First	AN0/RA1 input

	Delay	d'50'		;Aquisition time 50us
	bsf	ADCON0,2	;Set GO to start A/D conversion
YinStoreLoop
	btfsc	ADCON0,2	;A/D coversion Ready?
	goto	YinStoreLoop	;No. Go back.
				;Yes. Done.
	movf	ADRESH,W	;
	movwf	Yin		;*** Store Yin idle value (A/D).

	;Select then AN1/RA1 input
	bsf	ADCON0,3

	Delay	d'50'		;Aquisition time 50us
	bsf	ADCON0,2	;Set GO to start A/D conversion
XinStoreLoop
	btfsc	ADCON0,2	;A/D coversion Ready?
	goto	XinStoreLoop	;No. Go back.
				;Yes. Done.
	movf	ADRESH,W	;
	movwf	Xin		;*** Store Xin idle value (A/D).

	bcf	ADCON0,3	;Switch back to AN0/RA0 input.
	return

;*****************
CheckMouse

	;is there a mouse in use to start with?

	btfss	MOUSEINUSE	; = 1 if mouse bias was carried out successfullly
	return			; at power start-up. Else return and forget mice.
	
	;Mouse is there and it can be used, so go on:

	bcf	Xovl		;defaults
	bcf	Yovl
	bcf	Xsign
	bcf	Ysign
	
	call	ReadXY		;Read A/D input values into Xin and Yin

	;--Save Xin

	movf	Xin,W		;Compare present Xin to idle Xin value.
	subwf	Xidle,W		;Xin input is inverted => subtraction also inverted!
	bcf	Xsign		;set default = 0
	btfss	STATUS,0	;Borrow? (reversed borrow bit!)
	bsf	Xsign		;Yes. 
				;No.
	movwf	MouseByte3	;Save absolute Xin value to packet
	movwf	Xabs		;as default (2's complement if negative)

	;--SaveYin

	movf	Yidle,W		;Compare present Yin to idle Yin value. 
	subwf	Yin,W		;(Yin input is not inverted)
	bcf	Ysign		;set default = 0
	btfss	STATUS,0	;Borrow? (reversed borrow bit!)
	bsf	Ysign		;Yes.
				;No.
	movwf	MouseByte4	;Save absolute Yin value to packet
	movwf	Yabs		;as default (2's complement if negative)
	

	;Adjust Xin/Yin values according to curves
	;Measured voltage values at X and Y input pins are around 1V... 3V
	;Some values for reference:
	;Bias point 0x5f(95d) = 2V ; 0...1V <=> 0...0x2f(47d)
	;X and Y span: -1V...0...+1V <=> 0xd0...0...0x2f

	;Should this be sent?

	; For comparing, and scaling, calculate absolute values of X and Y
	; Convert negative 2's complement values (7F...FF) into
	; absolute values (0...FF)
	;  7F...FF 00 01 02...7E 
	;-127...-1  0  1  2...126

	btfss	Xsign		; MouseByte3 negative?
	goto	CheckMouse1	; No.
	movf	MouseByte3,W	; Yes. Convert. 
	sublw	0xFF		;
	movwf	Xabs		;
	incf	Xabs,F		; -1 = 0 incf=> -1 = 1 (because FF = -1)

CheckMouse1

	btfss	Ysign		; MouseByte4 negative?
	goto	CheckMouse2	; No.
	movf	MouseByte4,W	; Yes. Convert. 
	sublw	0xFF		;		
	movwf	Yabs		;
	incf	Yabs,F		; -1 = 0 incf=> -1 = 1 (because FF = -1)

CheckMouse2

	;Check if values are large enough to be sent, not just ripple
	;Do not send if within +/-10 around idle values (ripple = +/-10)

	;X first:

	movlw	RIPPLE		; W=10 (assuming RIPPLE=10)
	subwf	Xabs,W		; Xabs-10   0 1 2 3 4 5 6 7 8 9 A B C D E... 
	movwf	Xabs		;                      ...FE FF 0 1 2 3 4...
	movwf	MouseByte3	; Save subtracted Xabs to MouseByte3
				; Would be 2's complement if negative!
	btfss	STATUS,0	; Borrow? (reversed borrow bit!)
	goto	CM2aa		; Yes. Do not send.
				; No. Large enough for sending. Leave X data there
	incf	Xabs		; but eliminate zero value. 0,1,2,3,...=> 1,2,3,4,...
	incf	MouseByte3	;
	goto	CheckM2a	; 
CM2aa				; Yes. Xabs < 10, no need to send
	clrf	MouseByte3	; Clear all X data IF < 10.
	clrf	Xabs		; Xabs = MouseByte3:
	bcf	Xsign		; 1 2 3 4 5 6 7 8 9 0 A B C D E... before
	bcf	Xovl		; 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5... after

	;Y then:

CheckM2a

	movlw	RIPPLE		; W=10
	subwf	Yabs,W		; Yabs-10
	movwf	Yabs
	movwf	MouseByte4	; Save subtracted Yabs to MouseByte4
				; Would be 2's complement if negative!
	btfss	STATUS,0	; Borrow? (reversed borrow bit!)
	goto	CM2bb		; Yes. Do not send.
				; No. Large enough for sending. Leave Y data there
	incf	Yabs		; but eliminate zero value. 0,1,2,3,...=> 1,2,3,4,...
	incf	MouseByte4	;
	goto	CheckM2b	; 
CM2bb				; Yes. Yabs < 10, no need to send
	clrf	MouseByte4	; Clear all Y data IF < 10.
	clrf	Yabs		; Yabs = MouseByte4:
	bcf	Ysign		; 1 2 3 4 5 6 7 8 9 0 A B C D E... before
	bcf	Yovl		; 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5... after


CheckM2b

	;Check if any X or Y data present. X, Y: 

	movlw	d'0'		;Is MouseByte3 zero (no X data)?
	xorwf	MouseByte3,W	;
	bnz	CheckMSend	;No. Send the mouse movement data packet.

	movlw	d'0'		;Is MouseByte4 zero (no Y data)?
	xorwf	MouseByte4,W	;
	bnz	CheckMSend	;No. Send the mouse movement data packet.

				;Both X and Y data missing:

	goto	CheckMX		; -> DO NOT SEND POINTER DATA
				;but still, check button state...

CheckMSend

	; Xabs = MouseByte3: 1,2,3,4,5...FF (0x01...~0x5f in practice)
	; Yabs = MouseByte4: 1,2,3,4,5...FF (0x01...~0x5f in practice)

	; -> SEND POINTER DATA

	;***SCALING of Yabs and Xabs (no ripple value left):
	
;AFTER REMOVING IDLE RIPPLE, MORE SCALING OF X Y DATA WILL BE DONE HERE...

;	goto	ScalingExit	;<<<<TEST!!!!

;------------new code:
	;                 Step1   Step2 Step3 (see the #defines)
	;                 v       v     v 
	; 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14...
	; 1 1 1 1 1 1 1 1 2 2 2 2 3 3 3  4  5  6  7  8 
	; Steps 1...8 => 1
	;       9...c => 2
	;       d...f => 3
	;       10... => n-0x0d (e.g. 0x10-0x0C=0x04; decimal: 16-12=4)

; Xabs first


	movf	MouseByte3,W	; Is there any real value of X
	xorlw	d'0'		; X movement <> 0? (= 1,2,3,...)
	bz	ScalingXX	; No. Just check Y then.
				; Yes. Scale X.

	movf	Xabs,W
	movwf	TEMP	
	movlw	Step3		; Compare present Xabs to Step3 
	subwf	TEMP,W		; Xabs larger than Step3? (Xabs-Step3)
	btfsc	STATUS,0	; Borrow? (reversed borrow bit!)
	goto	ScalingX4	; No.
				; Yes. Borrow, Xabs < Step3
	movf	Xabs,W
	movwf	TEMP	
	movlw	Step2		; Compare present Xabs to Step2 
	subwf	TEMP,W		; Xabs larger than Step2? (Xabs-Step2)
	btfsc	STATUS,0	; Borrow? (reversed borrow bit!)
	goto	ScalingX3	; No. Xabs shall be equal to 3
				; Yes. Borrow, Xabs < Step2

	movf	Xabs,W
	movwf	TEMP	
	movlw	Step1		; Compare present Xabs to Step2 
	subwf	TEMP,W		; Xabs larger than Step1? (Xabs-Step1)
	btfsc	STATUS,0	; Borrow? (reversed borrow bit!)
	goto	ScalingX2	; No. Xabs shall be equal to 2
				; Yes. Borrow, Xabs < Step1

				; Xabs must be equal to 1
;ScalingX1
	movlw	1
	movwf	Xabs
	goto	ScalingXX

ScalingX2
	movlw	2
	movwf	Xabs
	goto	ScalingXX

ScalingX3
	movlw	3
	movwf	Xabs
	goto	ScalingXX

ScalingX4	;Larger than Step3
	movlw	Step3	; Subtract value: (Step3 - 3)
	subwf	Xabs,F	; Xabs - Step3
	movlw	d'3'
	addwf	Xabs,F	; Xabs - Step3 + 3

ScalingXX

	; Then Yabs

	movf	MouseByte4,W	; Is there any real value of Y
	xorlw	d'0'		; Y movement <> 0? (= 1,2,3...)
	bz	ScalingYX	; No. Just Exit scaling.
				; Yes. Scale Y.


	movf	Yabs,W
	movwf	TEMP	
	movlw	Step3		; Compare present Yabs to Step3 
	subwf	TEMP,W		; Yabs larger than Step3? (Yabs-Step3)
	btfsc	STATUS,0	; Borrow? (reversed borrow bit!)
	goto	ScalingY4	; No.
				; Yes. Borrow, Yabs < Step3

	movf	Yabs,W
	movwf	TEMP	
	movlw	Step2		; Compare present Yabs to Step2 
	subwf	TEMP,W		; Yabs larger than Step2? (Yabs-Step2)
	btfsc	STATUS,0	; Borrow? (reversed borrow bit!)
	goto	ScalingY3	; No. Yabs shall be equal to 3
				; Yes. Borrow, Yabs < Step2

	movf	Yabs,W
	movwf	TEMP	
	movlw	Step1		; Compare present Yabs to Step1 
	subwf	TEMP,W		; Yabs larger than Step1? (Yabs-Step1)
	btfsc	STATUS,0	; Borrow? (reversed borrow bit!)
	goto	ScalingY2	; No. Yabs shall be equal to 2
				; Yes. Borrow, Yabs < Step1

				; Yabs must be equal to 1
;ScalingY1
	movlw	1
	movwf	Yabs
	goto	ScalingYX

ScalingY2
	movlw	2
	movwf	Yabs
	goto	ScalingYX

ScalingY3
	movlw	3
	movwf	Yabs
	goto	ScalingYX

ScalingY4	;Larger than Step3
	movlw	Step3	; Subtract value: (Step3 - 3)
	subwf	Yabs,F	; Yabs - Step3
	movlw	d'3'
	addwf	Yabs,F	; Yabs - Step3 + 3


ScalingYX

	; Save the scaled values to packets too

	movf	Xabs,W
	movwf	MouseByte3
	movf	Yabs,W
	movwf	MouseByte4	


;-------------end of new code

	;Then, after scaling...


	;Convert absolute negative values (0...FF) back into 2's complement values (FF...1)
	;- these are the subtracted values (to eliminate ripple)

	btfss	Xsign		;MouseByte3 negative?
	goto	CheckMouse1b	;No. Leave as is.
	movf	Xabs,W		;Yes. Convert the subtracted and scaled value
	sublw	0xFF		;  back to 2's complement
	movwf	MouseByte3	;and save it into the packet
	incf	MouseByte3,f	; but -1 must give FF, so increment FE to FF etc

CheckMouse1b
	btfss	Ysign		;MouseByte4 negative?
	goto	SendButtons	;No. Leave as is.
	movf	Yabs,W		;Yes. Convert the subtracted and scaled value 
	sublw	0xFF		;  back to 2's complement
	movwf	MouseByte4	;and save it into the packet
	incf	MouseByte4,f	; but -1 must give FF, so increment FE to FF etc



SendButtons
	;CALL HERE if only button data will be sent.******

	;	LButton	= MouseByte1,0
	;	RButton	= MouseByte1,1
;MouseByte1 = 0  G  D5 D4 D3 D2 D1 D0
;	;0(mouse) MToggle Yovl Xovl Ysign Xsign RButton LButton

;MouseByte2 = - - - Z A3 A2 A1 A0  (A0-A2 = device address)
;	;(only 5 bits to be sent, A3=0, Z=1 for scroll wheel data)

	;Update Button status (RB7=LButton, RB6=RButton)

	bcf	LButton		;Set defaults
	bcf	RButton
	bcf	WButton
	btfss	PORTB,7		;Pull-ups: high=not pressed
	bsf	LButton		;Left button is down (pressed)
	btfss	PORTB,6
	bsf	RButton		;Right button is down (pressed)

	;Need to set MToggle Flag? Will this be a 'no buttons down' packet?

	btfsc	LButton
	goto 	SendB1
	btfsc	RButton
	goto 	SendB1

	bsf	MToggleFlag	;No buttons pressed so set Toggle Flag
	goto	ChM2bb		;and then just send the packet

SendB1
	;Button(s) are pressed
	;Need to change MToggle bit? MToggleFlag=1? If 'no button down' information
	; was sent last time, then change Toggle bit for next any button pressed

	btfss	MToggleFlag	;Toggle flag set?
	goto	ChM2bb		;No. No need to change Toggle bit

CheckMToggle
	movlw	b'01000000'	;A mouse button is pressed so change MToggle bit
	xorwf	MouseByte1,F	;Mouse Toggle bit = MouseByte1,6
				;
	bcf	MToggleFlag	;reset Toggle Flag as Toggle bit has now been changed


ChM2bb
	call	SendPointerData	;	***** SEND MOUSE PACKET

	;Save previously sent button states

	bcf	LButtonPrev	;Set defaults
	bcf	RButtonPrev
	bcf	WButtonPrev
	btfsc	LButton		;LButton in MouseByte1 zero (pressed)?
	bsf	LButtonPrev	;Left button was down
	btfsc	RButton		;RButton in MouseByte1 zero (pressed)?
	bsf	RButtonPrev	;Right button was down
	btfsc	WButton
	bsf	WButtonPrev	;Wheel button was down

	
	return

CheckMX
	;No pointer value to send, but check if Buttons are pressed?
	;LButtonIn	PORTB,7
	;RButtonIn	PORTB,6

	;(Need also to send released buttons 32 times)

	;Clear pointer data

	clrf	MouseByte3	;X movement data
	clrf	MouseByte4	;Y movement data
	btfss	LButtonIn	;1 = not pressed
	goto	CheckMXpressed
	btfsc	RButtonIn	;1 = not pressed
	goto	CheckMXnb	;No buttons are down

	;buttons are pressed:
CheckMXpressed
	movlw	d'32'		;initialize counter for 'no buttons pressed' packets
	movwf	maxMcounter
	goto	SendButtons	;Mouse Buttons are pressed, so send packet

	;No buttons pressed but still at least 32 packets must be sent
	;  to ensure that information on button release is sent.

	;no mouse buttons are pressed:
CheckMXnb	
	decfsz	maxMcounter,f	;Max number of 'no mouse buttons pressed' sent?
	goto	SendButtons	;No. Send
	incf	maxMcounter,f	;Yes. Prepare for next check.
				;Do not send.
	return
;*******************************************************************************

	END                     ; directive 'end of program'





