; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;                                                                     ;
;   gkpNNxp.asm is a further development of gkp23.asm to be able to   ;
;   use Windows XP with smart key polling and to enter chordons       ;
;   i.e. chord chains (chord on chord without release of all keys).   ;
;   Mouse simulation by using the GKOS keyboard has been improved.    ;
;   Also, development of US and FIN/SWE versions is combined now.     ;
;                                                                     ;
;   Interface: GKOS keyboard + mouse <=> PC PS/2 kbd/mouse connector  ;
;                                                                     ;
;           This file is for full remote control of the PC            ;
;                                                                     ;
;    GKOS keyboard and IR receiver <=> PS/2 connector interface       ;
; assembly code generation on the PICmicro PIC16F876 with 4 MHz clock.;
; Receives IR code and converts it to match the PS/2 protocols at     ;
; the PC's keyboard and mouse connector. Both mouse and keyboard      ;
; functions are supported. The GKOS remote control signals can be     ;
; transmitted by gkirXX.asm, another assembly code generator for the  ;
; PICmicro PIC16F876. It is also possible to directly connect a wired ;
; GKOS keyboard to this PS/2 connector interface. More at gkos.net    ;
;                                                                     ;
;              *** Note. Before assembling this file:                 ;
; Select whether US or FIN/SWE PC keyboard scan codes are used by     ;
; checking line 655 (or near it). Add or remove the ';' (commented    ;
; line or not). No other changes are required.                        ;
;                                                                     ;
;             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 -                   ;
;                                                                     ;
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;                                                                     *
;    Filename:	    gkxp24.asm                                        *
;    Date:          30 January 2005                                   *
;    File Version:  2.4                                               *
;                                                                     *
;    Author:        Seppo Tiainen, Veikkola, Finland                  *
;    Website:       gkos.net (building), gkos.com (specification)     *
;    Email:         gkos@gkos.com                                     *
;                                                                     * 
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;
;   Version history:
;
;   gkxp24.asm INTERIM VERSION FOR WIN XP - TO BE FINALIZED SOON
;   gkp23.asm  Wired GKOS functionality improved to the same as IR
;   gkp22.asm  Wired GKOS bug fixed (only IR functioned in gkos21.asm)
;   gkp21.asm  Introduces shortcuts for words in the Tab group (US/UK version)
;   gkp20.asm  Adjustments for key poll guard time and mouse trigger time,
;                 combines overlap and check-back versions again
;                 and adds LEDs: CAPS, 123, SYMB, spare (Port A RA2-5)
;   gkp19f     Autorepeat correction for mouse/kbd operations (;,,->;;;)
;   gkp19e     Debounce added for wired GKOS kbd polling
;   gkp19c     Some corrections - good operation, check-back only 
;   gkp19a     TextOnly parameter (only letters allowed within a chordon) added
;                and guard time (WaitCounter) made relative to chord period C
;   gkp19.asm  combines both overlap and check-back options
;   gkp18.asm  key pollig uses checking back of chords that are missed
;               because they are not followed by any key release
;   gkp17b.asm enhanced key polling allowing overlap of characters
;   gkp17.asm  drag and drop by kbd as mouse (SYMB=left button down, SHIFT=up)
;   gkp16b.asm better autorepeat for kbd as mouse, left click: SHIFT
;   gkp16.asm  kbd as mouse improved, autorepeat indication added again                                                                     
;   gkp15.asm  combines FIN/SWE and US keyboard versions into one file
;   gkp14.asm 
;   gkp12.asm  adds cleverer key polling to gkpc12.asm, some chordons possible
;
;---------------------------------------------------------------------|
;                                                                     |
;   If interrupts are not used all code presented between the ORG     |
;   0x004 directive and the label main can be removed. In addition    |
;   the variable assignments for 'w_temp' and 'status_temp' can       |
;   be removed.                                                       |                         
;                                                                     |
;   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.                               |
;                                                                     |
;---------------------------------------------------------------------|
;                                                                     |
;    Files required: p16f876.inc                                      |
;                                                                     |
;---------------------------------------------------------------------|

	list		p=16f876	; list directive to define processor
	#include	<p16f876.inc>	; processor specific variable definitions
	
	__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.
;
; turn off crossing page boundary messages while running the assembler:
;	ERRORLEVEL -306, -302
;
; base frequency
XTAL_FREQ	EQU	4000000	; OSC freq in Hz

; caulculates baudrate when BRGH = 1, adjust for rounding errors
#define CALC_HIGH_BAUD(BaudRate)	(((10*XTAL_FREQ/(16*BaudRate))+5)/10)-1

; caulculates baudrate when BRGH = 0, adjust for rounding errors
#define CALC_LOW_BAUD(BaudRate)		(((10*XTAL_FREQ/(64*BaudRate))+5)/10)-1

;
;============= GKOS INFORMATION =================
;
;              http://gkos.com (specifications)
;              http://gkos.net (build project)
;
;--------Infrared control data format:
;
;This procedure is repeated continuously by the remote IR data transmitter:
; scan keys first time > wait 5ms > If needed send Mouse report > wait 5ms >
; scan keys second time > send Chord value packet > repeat
;
;IR DATA PACKET FORMATS:
;
;-Format of Chord value packet:
;[start] D0 D1 D2 D3 D4 D5        - 6 bits -
;        G  1  A0 A1 A2           - 5 bits -  G=toggle, 1=keyboard
;
;-Format of Mouse data packets:
;[start] D0 D1 D2 D3 D4 D5        - 6 bits -
;        G  0  A0 A1 A2 A3 Z(=0)  - 7 bits -  G=toggle, 0=mouse, Z=0: pointer data
;        X0 X1 X2 X3 X4 X5 X6 X7  - 8 bits -  (pointer movement data)
;        Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7  - 8 bits -
; or:
;[start] D0 D1 D2 D3 D4 D5        - 6 bits -
;        G  0  A0 A1 A2 A3 Z(=1)  - 7 bits -  G=toggle, 0=mouse, Z=1: wheel data
;        Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7  - 8 bits -  (scroll wheel data)
;-------------------------------------------

;=================== VARIABLES: ==============================

;PIC 16F876 General Purpose Register locations are 0x20...0x7F (Bank 1)

TempB0		EQU     0x20	; Used to store bit locations in chord polling
TempB1		EQU     0x21
TempB2		EQU     0x22
TEMP0           EQU     0x23	; These TEMP1 to TEMP3 are used in the key polling
TEMP1           EQU     0x24	;   timer checks (see KeyTime)
TEMP2           EQU     0x25

;*** GKOS specific definitions

chord		EQU	0x26	; Chord at the reading moment
maxchord	EQU	0x27	; Max pressed combination before all keys released
finalchord	EQU	0x28	; Final key combination
GKOSstatus	EQU	0x29	; GKOS keyboard status bits
				;  bit0=1: chord received
				;  bit1=1 typematic on
				;  bit2=1 activity on GKOS noticed
				;  bit3=IR toggle bit (expected)
				;  bit4= RXchordREADY, IR Chord is ready for output to PS/2
				;  bit7-bit5: 
				;    bit7=1 IR operation (IR receiver connected) NOT USED
				;    bit6=1 IR packet received correctly
				;    bit5=1 'Kbd as Mouse' operation / bit5=0 Keyboard operation
GKOSref		EQU	0x2A	; GKOS character ref.number based on finalchord
                                ;  (the specified GKOS ref.num)
GKOSrefshift	EQU	0x2B	; 0, 63 or 126 (abc, 123 or SYMB tables) + GKOSref
GKOSmode	EQU	0x2C	; bit0:      abc-123 1=123,      0=abc
				; bit2/bit1: SYMB,  10=SYMBon,  11=SYMBlock
				; bit4/bit3: SHIFT, 10=SHIFTon, 11=SHIFTlock (CAPS LOCK)
				; bit5:      CTRL,   1=CTRLon 
				; bit6:      ALT,    1=ALTon  
				; bit7:      Paste on. (Still missing: NUMLOCK)
scpointer	EQU	0x2D	; Based on GKOSref, this points to the
				;  proper scan code in table
TempShift1		EQU	0x2E	; Temporary shift register

;**** Delay

dcount1		EQU	0x2F    ; Used in Delay subroutines 
dcount2		EQU	0x30		 
dcount3		EQU	0x31		 
dcount4		EQU	0x32		 

;**** PS/2 data/clock line communications

COUNTER		EQU	0x33		; bit counter for PS/2 comms
PARITY		EQU	0x34		; parity for PS/2 comms
RECEIVE		EQU	0x35		; PS/2 keyboard receiving buffer
Offset		EQU	0x36		; Table offset (scan codes etc.)
MRECEIVE	EQU	0x37		; PS/2 mouse receiving buffer

;*********

LoopCounter	EQU	0x38		; Temporary counter in loops
ZeroChords	EQU	0x38		; Zero Chord counter for wired GKOS keyboard polling routine
temp_a		EQU	0x39		; Temporary IR reception delay counters
temp_b		EQU	0x3A
temp_c		EQU	0x3B

				; Mouse bytes to be sent to Host (PC PS/2 lines):
				; bit7 bit6 bit5  bit4  bit3  bit2    bit1    bit0
MOUSE_BUTTONS	EQU	0x3C	; Yovf Xovf Ysign Xsign '1'  MidButt RButton LButton
MOUSE_X		EQU	0x3D	; X7... X0
MOUSE_Y		EQU	0x3E	; Y7... Y0
MOUSE_Z		EQU	0x3F	; '0'   '0'   5thButton   4thButton   Z3... Z0
				; - Z3...Z0 Scroll Wheel data zzzz, values: -8...+7

;---more PS/2 kbd communications

TEMPX		EQU	0x40
TXstatus	EQU	0x41	; bit0=1 => Return from ByteOut without sending.
				; bit1=1 <= There was Reception during ByteOut
TXBYTE		EQU	0x42	; The Original Byte to be sent
TXBYTEtemp	EQU	0x43	; The Actual byte sent
Temp		EQU	0x44	; Very temporary variable (USART tx bits)
Tmp2		EQU	0x44	; Very temporary variable
tempflags	EQU	0x45	; FLAGS: bit0=IR bit correctly received

;---PS2 flags----
PS2flags	EQU	0x46	; bit0=1 Keyboard enable (K_ENABLE) received from Host
				; bit1=1 Mouse enable (M_ENABLE) received from Host
				; bit3=1 US version of keyboard
				;...
				; bit6=1 JustScanned (Wired GKOS, do not scan yet)
				; bit7=1 MoreChords (in buffer RXfinalchord2) to be sent via PS2
TempShift2	EQU	0x47	; temp shift register
Tmp3		EQU	0x48	; temp chord in check-back
GKOScounter1	EQU	0x49	; Counter for JustScanned indication, Wired GKOS kbd
GKOScounter2	EQU	0x4A	; Counter for JustScanned indication, Wired GKOS kbd

;----------
;spare room
;---------

;---IR parameters---

IRmaxchord	EQU	0x50
RXfinalchord	EQU	0x51
IRflags		EQU	0x52	;bit0=1 PREVNZ previously receved IR chord is non-zero
				;bit1=1 THISNZ this IR chord is non-zero
				;bit2=1 RXchordREADY ready to send character to host
				;bit3=1 NoOutput (key polling) even if a key is released
				;bit4=1 NewChar (key polling), output if key is released
				;bit5=1 CheckBackOn
				;bit6=1 TextOnly allowed, chord is within a chordon
RXchord		EQU	0x53	; Chord received from wired keyboard or IR link

KeyTime0	EQU	0x54	; Counter for Key down period (255 > 0)
KeyTime1	EQU	0x55	; Counter for Key down period (255 > 0)
KeyTime2	EQU	0x56	; Counter for Key down period (255 > 0)
KeyTime3	EQU	0x57	; Counter for Key down period (255 > 0)
KeyTime4	EQU	0x58	; Counter for Key down period (255 > 0)
KeyTime5	EQU	0x59	; Counter for Key down period (255 > 0)

RXfinalchord2	EQU	0x5A	; Chord that was left in buffer because two chords must be output
				;  due to checking back in the key polling procedure
;KeysDown	EQU	0x5A	; Number of bits (keys down) in chord; see NewChar also.
				; If NewChar=1 and KeysDown decreases, a char is output
PrevChord1	EQU	0x5B	; Previous chord for key polling procedure
PrevChord2	EQU	0x5C	; 'Previous to previous' chord for key polling procedure
ToggleCounter	EQU	0x5D	; IR reception Toggle timer (polling, autorepeat)
Downs		EQU	0x5E	; Chord value to be output (keys down, polling)

;---Scancode parameters

scancode	EQU	0x5F ;temp place to store scancode
sc_buffer0	EQU	0x60
sc_buffer1	EQU	0x61
;sc_buffer2	EQU	0x62

;-----------

;--- more IR parameters

IRdevice	EQU	0x63	; IR Device code of this device (xxxa aadg = xxx1 11xx) a:210
IRinfopart	EQU	0x64	; Received information part of the IR packet:
				; x  x  x D6    D7 A0 A1 A2 (instead: use the IRByte2 received)
				; The received IR data bytes:
				; ---------------------------
IRByte1	EQU	0x65	; - chord value or mouse button etc data (extra bits A3 Z follow)
				; Chord: -  - D5   D4   D3    D2    D1      D0
				; Mouse: -  - Yovf Xovf Ysign Xsign RButton LButton  
IRByte2	EQU	0x66	; Device (A2-A0), mouse/chord bit d, toggle bit G (xxxa aadg)
				; Chord: xxxa aa1g: - - - A2 A1 A0 '1' TOGGLE 
				; Mouse: xxxa aa0g: - - - A2 A1 A0 '0' MTOGGLE
				; (Two bits A3 0/1 are sent here inbetween but not stored)
IRByte3	EQU	0x67	; X movement (X7...X0) or wheel data (0 0 0 0 Z3...Z0)
IRByte4	EQU	0x68	; Y movement data (Y7...Y0)

				; Bytes to send to the PS/2 interface (Send Bit0 first)
				; -----------------------------------
MouseByte1	EQU	0x69	; Yovl Xovl Ysign Xsign  '1'  MButton RButton LButton (pointer)
MouseByte2	EQU	0x6A	; Similar to IRByte3 (X7...X0)
MouseByte3	EQU	0x6B	; Similar to IRByte4 (Y7...Y0)
MouseByte4	EQU	0x6C	; '0' '0' 5thButton 4thButton Z3 Z2 Z1 Z0 (Scroll wheel data)
KMouseByte1	EQU	0x6D	; Yovl Xovl Ysign Xsign  '1'  MButton RButton LButton (kbd as mouse)

WaitCounter	EQU	0x6E	; counter for key polling, no not accept new key releases

;====
;spare room
;====

;Locations 0x71...0x7F (source: 16F876A template) 

w_temp		EQU	0x71		; variable used for context saving 
status_temp	EQU	0x72		; variable used for context saving
pclath_temp	EQU	0x73		; variable used for context saving
;
;====
;spare room
;====
;
;(max 0x7F)
;
; ------------------ Program memory pages: ------------------------------
; Page 0:    0h -  7FFh	2k	PCLATH need not be used for CALL and GOTO
; Page 1:  800h -  FFFh	4k	PCLATH<3>   must be used (set PCLATH<3>)
; Page 2: 1000h - 17FFh	6k	PCLATH<4,3> must be used (set PCLATH<4>)
; Page 3: 1800h - 1FFFh	8k	-"-                      (set PCLATH<4,3>)
; See Chapter 6.2.6 of 33023a.pdf for more.
;------------------------------------------------------------------------
;
;=================== DEFINITIONS:

;Note that PS/2 Data and Clock lines are brought to 0 (low) state by changing their
;appropriate I/O pins to output state. Original values must be 0 at those pins.
;Pull up resistors (4k7) are required if testing without connecting to a PC keyb socket.


#define CAPS_LED   	PORTA,4         ; LED (1=OFF) Clear the bit to turn LED on.
#define ABC123_LED   	PORTA,5         ; LED (1=OFF) 
#define SYMB_LED   	PORTA,6         ; LED (1=OFF)
#define spare_LED   	PORTA,7         ; LED (1=OFF)

#define CLOCK   	PORTC,3         ;=3 PS/2 connector keyboard clock line IN/OUT
#define DATA	  	PORTC,2         ;=2 PS/2 connector keyboard data line IN/OUT
#define MCLOCK   	PORTC,1         ;=1 PS/2 connector mouse clock line IN/OUT
#define MDATA	  	PORTC,0         ;=0 PS/2 connector mouse data line IN/OUT
#define TESTPOINT	PORTC,4		;=4 Test point (pin) for IR reception timing

#define	IRDATA		PORTB,6		; IR Data input. Low when IR pulse. Internal pull-up used.
#define	RXTOGGLE	IRByte2,0	; <---IRinfopart,0	; Received kbd toggle bit value
#define	AutoRepeat	GKOSstatus,1	; autorepeat indication
#define TOGGLE		GKOSstatus,3	; Expected kbd toggle bit value
#define PREVNZ		IRflags,0	; previous IR chord was non-zero
#define	THISNZ		IRflags,1	; this IR chord is non-zero
#define NoOutput	IRflags,3	; no character output even if a key is released (IR)
#define NewChar		IRflags,4	; new character output if any key released (IR)
#define RXchordREADY	GKOSstatus,4	; bit4=1 IR Chord ready for output to PS/2
					; Next timing periods are N x 30 ms:
#define	TDelay		d'30'		; (d'25') Autorepeat delay (cleverer polling)
#define	MTDelay		d'7'		; (d'8') Mouse Autorepeat delay
#define	WaitPeriods	d'5'	; (d'5'ok) WaitCounter value after key release (key polling)
					;   only valid in case of no check-back in use
#define CheckBackOn	IRflags,5	; Check-back is enabled.
#define TextOnly	IRflags,6	; Chord is within a chordon. Text only allowed, or space.


#define	K_ENABLE	PS2flags,0	; Keyboard ENABLE received from Host
#define	M_ENABLE	PS2flags,1	; Mouse ENABLE received from Host
#define	US_version	PS2flags,3	; US version of keyboard in use
					; ...
#define JustScanned	PS2flags,6	; Wired GKOS kbd, do not scan yet
#define GKOSdelay	d'25'		; Delay before re-scanning the wired GKOS
#define MoreChords	PS2flags,7	; There is a chord in buffer RXfinalchord2 to be sent via PS2

#define	KBDasMOUSE	GKOSstatus,5	; Mouse operation through GKOS keys in ON

#define	MODE123on	GKOSmode,0	
#define	SYMBlock	GKOSmode,1
#define	SYMBon		GKOSmode,2
#define	SHIFTlock	GKOSmode,3
#define	SHIFTon		GKOSmode,4
#define	CTRLon		GKOSmode,5
#define	ALTon		GKOSmode,6
#define	PASTEon		GKOSmode,7



;**********************************************************************
	ORG     0x000             ; processor reset vector
	nop			  ; nop required for icd
  	goto    main              ; go to beginning of program


;***** INTERRUPT ROUTINE: *********************************************

	ORG     0x004             ; interrupt vector location
	movwf   w_temp            ; save off current W register contents
	movf	STATUS,w          ; move status register into W register
	movwf	status_temp       ; save off contents of STATUS register
	movf	PCLATH,w	  ; move pclath register into w register
	movwf	pclath_temp	  ; save off contents of PCLATH register

;   isr code can go here or be located as a call subroutine elsewhere

	movf	pclath_temp,w	  ; retrieve copy of PCLATH register
	movwf	PCLATH		  ; restore pre-isr PCLATH register contents
	movf    status_temp,w     ; retrieve copy of STATUS register
	movwf	STATUS            ; restore pre-isr STATUS register contents
	swapf   w_temp,f
	swapf   w_temp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt

;================== Macros ======================================= 

Delay   macro   Time            ;Delay 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 

;===================== ....more macros...

;---PS/2 keyboard lines:

DATA_0		Macro
		bsf	STATUS, RP0 	;Reg Bank 1
		bcf	DATA		;Switch to output mode
		bcf	STATUS, RP0 	;Reg Bank 0
		bcf	DATA		;Write 0 to output
		endm

DATA_1		Macro
		bsf	STATUS, RP0	;Switch back to input mode
		bsf	DATA
		bcf	STATUS, RP0
		nop
		endm

CLOCK_0		Macro
		bsf	STATUS, RP0 	;Reg Bank 1
		bcf	CLOCK		;Switch to output mode
		bcf	STATUS, RP0 	;Reg Bank 0
		bcf	CLOCK		;Write 0 to output
		endm

CLOCK_1		Macro
		bsf	STATUS, RP0	;Reg Bank 1
		bsf	CLOCK		;Switch back to input mode
		bcf	STATUS, RP0	;Reg Bank 0
		nop
		endm

;---PS/2 mouse lines:

MDATA_0		Macro
		bsf	STATUS, RP0 	;Reg Bank 1
		bcf	MDATA		;Switch to output mode
		bcf	STATUS, RP0 	;Reg Bank 0
		bcf	MDATA		;Write 0 to output
		endm

MDATA_1		Macro
		bsf	STATUS, RP0	;Switch back to input mode
		bsf	MDATA
		bcf	STATUS, RP0
		nop
		endm

MCLOCK_0		Macro
		bsf	STATUS, RP0 	;Reg Bank 1
		bcf	MCLOCK		;Switch to output mode
		bcf	STATUS, RP0 	;Reg Bank 0
		bcf	MCLOCK		;Write 0 to output
		endm

MCLOCK_1		Macro
		bsf	STATUS, RP0	;Reg Bank 1
		bsf	MCLOCK		;Switch back to input mode
		bcf	STATUS, RP0	;Reg Bank 0
		nop
		endm


;======================= ...end of macros ===========================


;********************** MAIN *****************************************
;				Memory blocks
; Reset vector     0000h (RAM)
; Interrupt vector 0004h (RAM)
;
; Program memory Pages (PROM): 
; P0 0005h-07FFh Program...
; P1 0800h-0FFFh ....More Program Code
; P2 1000h-17FFh (spare)
; P3 1800h-1FFFh Character and Scancode Tables
; 
;
;*********************************************************************;
;__________________________ P0 0005h-07FFh Program..._________________;

main

;===================== INITIALIZE PARAMETERS =========================
	clrf	PORTB		; clear port B

				; Set Bank 1 registers
				; --------------------
				;
	bsf	STATUS,RP0      ; change to register bank 1
	bcf	STATUS,RP1

	bcf	OPTION_REG,7	; ...for bank 1 OPTION_REG: clear bit 7 for pull-ups
				;  on port B (GKOS keys + IR input line)

	; UART Bank 1 settings are here.
        ; for UART, the TRISC:6 and TRISC:7 must be set
	; (as for output, but operates as input/output)
	bsf	TRISC,6
	bsf	TRISC,7

				; Port C
				; ------
	movlw	b'10101111'	; binary value, 1 bit per port bit
	movwf	TRISC		; RC0 MouseDataOut/In, RC1 MouseClockOut/In (set to INPUTS) 
				; RC2 KeybDataOut/In,  RC3 KeybClockOut/In  (set to INPUTS)
				; - INPUTS simulate open collector on CLOCK and DATA lines
				; RC4 output: TEST POINT OUTPUT (for IR timing)
				; RC5 USART RXdata input
				; RC6 USART TXdata ouput
				; RC7 spare input

				; Port B - GKOS keys
				; ------
	movlw	b'01111111'	; binary value, 1 bit per port bit
	movwf	TRISB		; RB0-RB6 set to digital inputs, GKOS keys + IR data in
				; (RB7 is PORTB output, not used)
				;  RB0-RB5 Keyboard
				;  RB6     IR data input

				; Port A - LED indicators (CAPS/SHIFT, SYMB, 123-ABC)
				; ------
	movlw	b'11000011'	; binary value, 1 bit per port bit
	movwf	TRISA		; RA0-1, RA6-7  set to inputs (A/D converter in IR remote control)
				; RA2-5 outputs for LEDs

				;Any other settings for Bank 1 registers?

				; Return to Bank 0
				; ----------------
	bcf	STATUS,RP0	; change to register bank 0


	call	INIT_UART	;*** USART Transmission - write to reg. 19h TXREG

	movlw	b'00111100'
	movwf	PORTA		; ALL LEDS OFF/output to high state (CAPS, 123, SYMB, spare)
	clrf	TXstatus	; Clear flags and parameter values
	clrf	RECEIVE
	clrf	chord
	clrf	RXchord
	clrf	RXfinalchord2
	clrf	PrevChord1
	clrf	PrevChord2
	clrf	Downs
	clrf	WaitCounter
	clrf	ZeroChords
	clrf	maxchord
	clrf	IRmaxchord
	clrf	finalchord
	clrf	RXfinalchord
	clrf	GKOSstatus
	clrf	GKOSref
	clrf	GKOSrefshift
	clrf	GKOSmode
	clrf	PS2flags
	clrf	IRflags
	clrf	MouseByte1
	clrf	KMouseByte1

		;IR data formats.  SIRC spec: 01111 = MD
		;MD 0001000 11110 / GKOS: 000100 01111(0) = cccccc gdaaa(0) <on oscilloscope
		;MD: 7 + 5 = 12 bits / GKOS: 6 + 5 = 11 bits. Received order: xxxa aadg
	movlw	b'00011100'	;Set the default IR device code in reverse order (xxxa aadg)
	movwf	IRdevice	;Sending order: x x x A2  A1 A0 D7 D6; SIRC spec: 01111 = MD 
				;D6=G (character toggle bit)
				;D7=1 for keyboard and 0 for mouse. A0-A2 = device address

	;movlw	d'100'		;Delay before sending 'GKOS' via USART at 9600 bit/s
	;call	DelayWx10ms	; - this will test that debug monitor is working

				; FAR CALL address:
				;    X XCCC CCCC CCCC (PC<12:0>)
				;  PCLATH-- -PCLATL--
				;    H HHHH LLLL LLLL
				;   12 1098 7654 3210
	;movlw	HIGH TestUSART	; Get high 5 bits of address
	;movwf	PCLATH		; Load high address in latch
	;call	TestUSART	; send text: GKOS <CR> to USART (pin RC6)
	;movlw	HIGH BAT	; Make sure PCLATH is pointing to this Page (0)
	;movwf	PCLATH

	;movlw	d'50'
	;call	DelayWx10ms

;========================================================================
;---- Select here whether US or FIN/SWE PC keyboard is being replaced ---
; This sets the default national keyboard version (US/UK or FIN/SWE) only.
; The version can always be changed by typing ALT 123-ABC (Alternative mode)
;
	bsf	US_version	; This selects US version and must be
				; a commented line for FIN/SWE version
;----------------------------------------------------------------------
	bsf	CheckBackOn	; Enable check-back of missed chords
				; - comment the line to disable
;=========================================================================


; Basic assurance test results are reported to host


	bsf	K_ENABLE 	; Default for XP 2005


BAT
	call	BATsub
	goto	MainLoop

BATsub
	movlw	d'50'
	call	DelayWx10ms
	call	SendBAT		; Keyboard
	movlw	d'1'
	call	SerTx1		;debug
	return

MBAT
	movlw	d'165'	;	1.65s (LEDs on and off)
	call	DelayWx10ms
	call	MSendBAT	; Mouse
	movlw	d'2'
	call	SerTx1		;debug


;============================ PROGRAM ==================================
; The device should check 'request to send' from host (=DATA pulled low)
; at least every 10ms!

MainLoop

	 Delay	d'100'		;delay 100us

;------------------------
;===== PS/2 KEYBOARD ====
;------------------------
MainL_Keyboard


	; In case previous chord was zero, any next caracter must be allowed next
	incf	RXchord,f	; RXchord=0?
	decfsz	RXchord,f
	goto	ML_K0
	bcf	TextOnly	; Allow any character next because it is not part of a chordon.
ML_K0


		; Check PS/2 keyboad lines: Host Requesting to send?
		; =========================

				;==POLL Host keyboard data line==

	btfsc	DATA		;Is DATA pulled low by Host?
	goto	MainL_Mouse	;No.  Keep on polling other inputs...
	call	ByteIn		;Yes. Receive one byte into RECEIVE register.
		;Add here: ByteIn successful?

; Kbd sends ACK to all but 'Resend' and 'Echo' commands
; Resend: just resend the last Scan code

	movlw	0xee		;Echo received?
	xorwf	RECEIVE,W	;
	bnz	MainL_K1	;
	call	SendEcho	;Yes. Just send Echo (=0xee)
	goto	MainLoop

; (Resend not yet implemented)

MainL_K1

	movlw	0xf2		; Read ID received?
	xorwf	RECEIVE,W	;
	bnz	$ + 3		; No.	
	call	SendID		; Yes. Send Keyboard ID = 0xab 0x83 (+1)
	goto	MainLoop	; (+2)
				; (+3)
	call	SendACK		;Acknowledge all other bytes by default (ack: 0xfa).

;	movlw	0xf2		;Read ID received?
;	xorwf	RECEIVE,W	;
;	btfsc	STATUS,Z	;
;	call	SendID		;Yes. Send Keyboard ID = 0xab 0x83

;	movlw	0xf2		; Read ID received? *****THIS IS A BETTER WAY****
;	xorwf	RECEIVE,W	;
;	bnz	$ + 3		; No.	
;	call	SendID		; Yes. Send Keyboard ID = 0xab 0x83
;	goto	MainLoop
	
	movlw	0xff		;Reset 0xff received?
	xorwf	RECEIVE,W	;
	btfsc	STATUS,Z	;
	goto	BAT		;Yes. Go back to BAT (again, do selftest and send 0xaa)

	movlw	0xf5		; Keyboard DISABLE 0xf5 received?
	xorwf	RECEIVE,W	; Scan codes can no more be sent to Host.
	btfsc	STATUS,Z	; 
	bcf	K_ENABLE	; Yes. DISABLE received.
				; No.

;----lastly:
	movlw	0xf4		; Keyboard ENABLE 0xf4 received?
	xorwf	RECEIVE,W	; Last command of PS/2 keyboard setup.
	btfss	STATUS,Z	; ...after this, mouse can be initialized.
	goto	MainL_Mouse	; No.
	bsf	K_ENABLE	; Yes. Indicate that scan codes can be sent to Host.
	goto	MBAT		; Go to MBAT (do selftest delay and send 0xaa 0x00)

;---------------------
;===== PS/2 MOUSE ====
;---------------------
MainL_Mouse

	;Delay	d'100'		;delay 100us <= is this delay needed any more?

		; Check PS/2 mouse lines: Host Requesting to send?
		; =======================

	;goto	MainL_GKOS	;<<<<TEST!!!!!

				;==POLL Host mouse data line==

	btfsc	MDATA		;Is DATA pulled low by Host?
	goto	MainL_GKOS	;No.  Keep on polling other inputs...
	call	MByteIn		;Yes. Receive one byte into MRECEIVE register.
			;Add here: MByteIn successful?

; Send ACK to all commands

;MainL_M1
	call	MSendAck	;Acknowledge all by default (ack: 0xfa).

	movlw	0xf2		;Read ID received?
	xorwf	MRECEIVE,W	;
	btfsc	STATUS,Z	;
	call	MSendID	;Yes. Send Mouse ID = 0x00

;	movlw	0xee		; 'Set Wrap Mode' received?
;	xorwf	MRECEIVE,W	;
;	btfsc	STATUS,Z	;
;	call	....		;Yes. Mouse shall echo all

;NOT IMPLEMENTED:
; 1) Set Wrap Mode
; 2) Remote Mode
	
	movlw	0xff		;Reset 0xff received?
	xorwf	MRECEIVE,W	;(Mouse: send 0xaa 0x00 then wait for enable
	btfsc	STATUS,Z	; command 0xf4 before sending any movement/button data)
	goto	MBAT		;Yes. Go back to Mouse BAT

	movlw	0xec		;'Reset Wrap Mode' 0xec received?
	xorwf	MRECEIVE,W	;(Mouse: send 0xaa 0x00 then return to Stream Mode
	btfsc	STATUS,Z	;        or Remote Mode)
	goto	MBAT		;Yes. Go back to Mouse BAT

	movlw	0xe9		;Mouse Status request received?
	xorwf	MRECEIVE,W	;
	btfsc	STATUS,Z	;
	call	MSendStatus	;Yes. Send Mouse Status = 0x00 0x02 0x64 (fixed values)

	movlw	0xf5		; Mouse DISABLE 0xf5 received?
	xorwf	MRECEIVE,W	; Scan codes can no more be sent to Host.
	btfsc	STATUS,Z	; 
	bcf	M_ENABLE	; Yes. Mouse DISABLE received.
				; No.

	movlw	0xf4		; Mouse ENABLE 0xf4 received?
	xorwf	MRECEIVE,W	; Scan codes can no more be sent to Host.
	btfsc	STATUS,Z	; 
	bsf	M_ENABLE	; Yes. Mouse ENABLE received.
				; No.

;------------------------------
;==== Wired GKOS keyboard =====
;------------------------------
MainL_GKOS

		; Any chords in buffer to send?

	btfss	MoreChords	; More chords to be sent? Due to Check-back.
	goto	MainL_GKOS_2	; No. Check wired GKOS and IR reception next.
				; Yes.
	movf	RXfinalchord2,W	; Get the chord from buffer.
	movwf	RXfinalchord	; Save it for transmission.
	clrf	RXfinalchord2	; Clear buffer to make sure...
				; (MoreChords sometimes may be '1' in error!)

	btfss	DATA		;Is Keyboard DATA line pulled low by Host?
	goto	MainLoop	;Yes.  Go back...
	btfss	MDATA		;Is Mouse DATA line pulled low by Host?
	goto	MainLoop	;Yes.  Go back...

	; Host is not busy so data can be sent to Host

	bcf	MoreChords	; Clear flag to avoid repeating this.
	call	PS2SendChord_2	; Send RXfinalchord2 (now in RXfinalchord) via
	goto	MainLoop	;   PS2 keyboard data/clock lines.

MainL_GKOS_2

		; Check the wired GKOS keyboard: Any keys pressed.
		; =============================

	call	ReadGKOSchord   ; No. Scan, return, when keys released, with param. finalchord
	btfss	GKOSstatus,0	; Was there any key pressed? bit0 = 1?
	goto	MainL_IR	; No, continue by POLLING IR reception
				; Yes.

; ----NEW CODE to use same key polling routines as for IR reception

	; Chord data received

	btfss	DATA		;Is Keyboard DATA line pulled low by Host?
	goto	MainLoop	;Yes.  Go back...
	btfss	MDATA		;Is Mouse DATA line pulled low by Host?
	goto	MainLoop	;Yes.  Go back...

	; Host is not busy so IR data can be sent to Host

	call	PS2SendChord	; Send RXchord via PS2 keyboard data/clock lines.

; ------------

;----------------------
;==== IR RECEPTION ====
;----------------------
MainL_IR

		; Check the IR reception: any start pulse detected?
		; ======================

	call	CheckIR		; Check IR reception.
				; ==================
	movwf	TEMPX		; bits 0,1,2 and 7 in W indicate results of IR reception
	btfsc	TEMPX,7		; No proper IR data received? (Use TEMPX to store W)
	goto	MainLoop	;  -Right. Skip the rest.

	; IR data rceived

	btfss	DATA		;Is Keyboard DATA line pulled low by Host?
	goto	MainLoop	;Yes.  Go back...
	btfss	MDATA		;Is Mouse DATA line pulled low by Host?
	goto	MainLoop	;Yes.  Go back...

	; Host is not busy so IR data can be sent to Host

	btfss	TEMPX,0		; Chord IR data received?
	goto	MainL_IRa	; No.
	call	PS2SendChord	; Yes. Send it via PS2 keyboard data/clock lines.
	goto	MainLoop
MainL_IRa
	btfss	TEMPX,1		; Movement IR data received?
	goto	MainL_IRb	; No.
	goto	PS2SendMov	; Yes. Send it via PS2 mouse data/clock lines.
MainL_IRb
	btfsc	TEMPX,2		; Scroll wheel IR data received?
	call	PS2SendScroll	; Yes. Send it via PS2 mouse data/clock lines.

;---------

	goto	MainLoop
;------------- STRING OUTPUT ------------
Word_shortcuts
	btfsc	MODE123on	; return if this is set
	goto	Word_shortcuts_X
	btfsc	SYMBon		; return if this is set
	goto	Word_shortcuts_X
	btfsc	CTRLon		; return if this is set
	goto	Word_shortcuts_X
	btfsc	ALTon		; return if this is set
	goto	Word_shortcuts_X

	xorlw	d'5'		;Test if chord=with
	btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
	goto	PS2word_with	;

	movf	finalchord,W	;
	xorlw	d'13'		;Test if chord=and
	btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
	goto	PS2word_and	;

	movf	finalchord,W	;
	xorlw	d'21'		;Test if chord=the
	btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
	goto	PS2word_the	;

	movf	finalchord,W	;
	xorlw	d'37'		;Test if chord=that
	btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
	goto	PS2word_that	;

	movf	finalchord,W	;
	xorlw	d'29'		;Test if chord=have
	btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
	goto	PS2word_have	;

	movf	finalchord,W	;
	xorlw	d'53'		;Test if chord=which
	btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
	goto	PS2word_which	;

	movf	finalchord,W	; chord must be in W
	goto	Word_shortcuts_X
; ---
PS2word_with
	;movlw	d'40'	; w THESE HAVE BEEN UPDATED ACCORDING TO WORD FREQUENCIES IN ENGLISH
	;call	PS2Output
	;movlw	d'26'	; i
	;call	PS2Output
	movlw	d'14'	; t NOW: 'TH' because this is more common than many single letters
	call	PS2Output
	movlw	d'25'	; h
	call	PS2Output
	return
PS2word_and
	movlw	d'1'	; a
	call	PS2Output
	movlw	d'52'	; n
	call	PS2Output
	movlw	d'8'	; d
	call	PS2Output
	movlw	d'56'	; space
	call	PS2Output
	return
PS2word_the
	movlw	d'14'	; t 'the_'
	call	PS2Output
	movlw	d'25'	; h
	call	PS2Output
	movlw	d'16'	; e
	call	PS2Output
	movlw	d'56'	; space
	call	PS2Output
	return
PS2word_that
	;movlw	d'14'	; t
	;call	PS2Output
	;movlw	d'25'	; h
	;call	PS2Output
	movlw	d'3'	; o NOW: 'of_'
	call	PS2Output
	movlw	d'32'	; f
	call	PS2Output
	movlw	d'56'	; space
	call	PS2Output
	return
PS2word_have
	;movlw	d'25'	; h
	;call	PS2Output
	movlw	d'1'	; a NOW: 'a_'
	call	PS2Output
	;movlw	d'38'	; v
	;call	PS2Output
	;movlw	d'16'	; e
	;call	PS2Output
	movlw	d'56'	; space
	call	PS2Output
	return
PS2word_which
	;movlw	d'40'	; w
	;call	PS2Output
	;movlw	d'25'	; h
	;call	PS2Output
	;movlw	d'26'	; i
	;call	PS2Output
	movlw	d'14'	; t NOW: 'to_'
	call	PS2Output
	movlw	d'3'	; o
	call	PS2Output
	movlw	d'56'	; space
	call	PS2Output
	return
; ---
PS2Output
	movwf	Temp
	movlw	d'3'
	call	DelayWx1ms
	movf	Temp,W
	goto	PS2Output_0
;----------------------------------------

	; From IR reception and from wired GKOS:
	; NOTE This is a SUB since version gkp21.asm !!!

PS2SendChord	; W = 0x01 CHORD VALUE IR data received (bit0=1)
	;movlw	d'1'		;debug
	;call	SerTx		;

;------
; THIS IS A FAR CALL, SO PROGRAM MEMORY PAGE MUST BE CHANGED
					;    X XCCC CCCC CCCC (PC<12:0>)
					;  PCLATH-- -PCLATL--
					;    H HHHH LLLL LLLL
					;(12)C BA98 7654 3210
	movlw	HIGH GetChordParams	; Get high 5 bits of address
	movwf	PCLATH			; Next Page...
	call	GetChordParams		; Do the common IR/wired keyboard procedure
	movlw	HIGH PS2SendChord 	; Make sure PCLATH is pointing to this Page (0)
	movwf	PCLATH

;------zxcvb
	btfss	RXchordREADY	; A chord to send?
	return			; No.

PS2SendChord_2
				; Yes. Check if NUL (due to polling back in time)
	movf	RXfinalchord,W	;
	xorlw	d'0'		; Test if chord=NUL
	btfsc	STATUS,Z	; Skip if Z=0. Skip if not equal.
	return			; Return to MainLoop

	movf	RXfinalchord,W
PS2Output_0	; Enter here when Sending a shortcut string (chord in W)
	movwf	finalchord

		; The chord has been confirmed

	btfsc	K_ENABLE	; Is Host ready to receive scan codes? (=ENABLE sent by the Host?)
	goto	PS2Output_1	; Yes.
	call	BATsub		; No. Try Keyboard BAT then.
	return	; goto	MainLoop	; No.
				; Yes.
PS2Output_1
	btfsc	KBDasMOUSE	; Is the GKOS keyboard simulating a mouse?
	goto	KeyboardMouse	; Yes. Send corresponding button/movement data via PS/2 mouse lines
				; No. Send scan codes via PS/2 keyboard lines.

	movf	finalchord,W	; is this really needed?
	call	SerTx		;debug
	
	;return			;<<<<<TEST!!!!!

		; In all cases, Chord is in W and finalchord

	;call	SerTx		;debug
	;movf	finalchord,W	; is this really needed?
	
		; finalchord must be in W

	btfsc	US_version	; If US version, check for word shortcuts
	goto	Word_shortcuts
Word_shortcuts_X
	btfsc	TextOnly	; Is this within a chordon?
	goto	PS2SC_2b	; Yes, skip the special functions below

	xorlw	d'63'		;Test if chord=123-abc
	btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
	goto	abc123Pressed	;

	movf	finalchord,W	;
	xorlw	d'45'		;Test if chord=SYMB
	btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
	goto	SymbPressed		;

	movf	finalchord,W	;
	xorlw	d'18'		;Test if chord=SHIFT
	btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
	goto	ShiftPressed		;

	movf	finalchord,W	;
	xorlw	d'47'		;Test if chord=CTRL
	btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
	goto	CtrlPressed		;

	movf	finalchord,W	;
	xorlw	d'55'		;Test if chord=ALT
	btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
	goto	AltPressed		;


PS2SC_2b
;====================== USE THE TABLES =========================

	;*** Check the tables for proper scan codes ***

;Functioning like this: finalchord => GKOSref => scpointer => scancode

			;Based on finalchord:
	clrf	GKOSrefshift	;clear table shift to start with
	call	FinalChordToGKOSref 	;Get the corresponfing GKOS Reference number
				    	;-> saved in: GKOSref

			; Key Polling: test if GKOSref > 30
			; If TextOnly=1 then do not accept funtions (within chordons)

	btfss	TextOnly	; Chord within a chordon?
	goto	ChordonOK	; No. Accept any character.
				; Yes. 
	movlw	d'31'		; Discard characters if GKOSref > 30
	subwf	GKOSref,W	; GKOSref - 31 = positive or zero?
	btfss	STATUS,C	; Carry staying zero? Note: C = complement of Borrow
	goto	ChordonOK	; No. Carry set. Then GKOSref < 31. No more action.
				; Yes. GKOSref > 30.
				; Check if 'space': GKOSref = 50?
	movlw	d'50'		; GKOSref=50?
	subwf	GKOSref,W	;
	btfss	STATUS,Z	; Z=1 ?
	return	; goto	MainLoop	; No. Z=0 / GKOSref <> 50. Just send nothing.
	;goto	ChordonOK	; Yes. Space is OK within a chordon.

ChordonOK
	bsf	TextOnly	; Set default for next character:
				; Send only GKOS chars 1-30 or space until zero chord found.
				; Assumed: chord is within a chordon.

	;Select proper GKOS character set based on SYMB and 123-abc

;************* Choose GKOS symbol set *************

	btfss	MODE123on	;123-mode on?
	goto	CheckSymb	;if not, continue
	movlw	d'63'		;if yes, use next table (123-table)
	movwf	GKOSrefshift	;Move down to 123-mode table
	btfss	SYMBon		;In addition to 123 mode, is SYMB on?
	goto	CheckX		;No. No more action then.
	movlw	d'0'		;Yes, SYMB is on in addition to 123 on. <> 26.4.2002
	movwf	GKOSrefshift	;...move back to abc set then
	movlw	d'31'		; but still use SYMB table if GKOSref>30 (:;_ etc)
	subwf	GKOSref,W	;GKOSref - 31 = positive or zero?
	btfss	STATUS,C	;Carry staying zero? Note: C = complement of Borrow
	goto	CheckX		;No. Carry set. Then GKOSref < 95. No more action.
	movlw	d'126'		;Yes. Use SYMB set (GKOSref .
	movwf	GKOSrefshift	;Shift to SYMB set.
	goto	CheckX
CheckSymb			;This SYMB check is in abc mode only (see above for 123 mode)
	btfss	SYMBon	;bits2&1: 10,11
	goto	CheckX		;no, just continue
	movlw	d'126'		;yes, use SYMB table
	movwf	GKOSrefshift	;Mode two sets down to SYMB table
CheckX
	movf	GKOSref,W	;use the selected shift in tables (abc,123,SYMB)
	addwf	GKOSrefshift,F	;GKOSrefshift The final pointer = ref + shift now

	btfsc	US_version	; US version of tables in use?
	goto	Check_US	; Yes.
	call	GKOSrefToScPointer	;No. Get the corresponding F/S Scan Code Pointer
	goto	CheckXX			;-> saved in: scpointer
Check_US
	call	US_GKOSrefToScPointer	;Get the corresponding US Scan Code Pointer
CheckXX
	call	ScPointerToScancode   	;Get the scan code pointed at,
					;-> saved in: scancode			    
	movf	scancode,W		;save the first scancode also into W and sc_buffer0
	movwf	sc_buffer0

;----------- SEND THE SCANCODES -----------
	
	movf	scancode,W
	andlw	0xf0		;is it a one-byte code? (0xe0=scan code of two bytes)
	xorlw	0xe0		;= 0xey? (0xe5 = shift required, 0xe6 = alt gr req'd)
	btfss	STATUS,Z	;is zero bit set in Status Register?
	goto	SendCode_basic	;Not zero = not equal to 0xey. The Basic 1-byte case.
				;Yes. Zero = equal to 0xey
	movf	scancode,W	;test again but now if it is equal to 0xe0	
	xorlw	0xe0
	btfsc	STATUS,Z	;is zero bit set?
	goto	SendCode_basic2	;Yes, it is 0xe0, Goto the basic 2-byte case.

				;Not set. Some special case (0xey but not 0xe0).
				;0xe5: add SHIFT, 0xe6: add ALT GR, ...

	movf	scancode,W	;test again but now if it is equal to 0xe5	
	xorlw	0xe5		;SHIFT + one byte scan code
	btfsc	STATUS,Z	;is zero bit set?
	goto	SendCode_Shift	;yes, equal

	movf	scancode,W	;test again but now if it is equal to 0xa6	
	xorlw	0xe6		;ALT GR + one byte char
	btfsc	STATUS,Z	;is zero bit set?
	goto	SendCode_AltGr  ;yes, equal

	movf	scancode,W	;test again but now if it is equal to 0xea	
	xorlw	0xea
	btfsc	STATUS,Z	;is zero bit set?
	goto	SendWordLeft	;yes equal

	movf	scancode,W	;test again but now if it is equal to 0xeb	
	xorlw	0xeb
	btfsc	STATUS,Z	;is zero bit set?
	goto	SendWordRight	;yes equal

	movf	scancode,W	;test again but now if it is equal to 0xe7	
	xorlw	0xe7
	btfsc	STATUS,Z	;is zero bit set?
	goto	SendPause	;yes equal

	movf	scancode,W	;test again but now if it is equal to 0xe8	
	xorlw	0xe8
	btfsc	STATUS,Z	;is zero bit set?
	goto	SendPrintScreen	;yes equal

	return	; goto	MainLoop
;--------------------------------------------------------------


;--------------------- THE TABLE CALLS ARE HERE ---------------
			;Read data

;Table_ChordToRef => Table_GKOSrefToScPointer (F/S or US) => Table_ScanCodes_abc

FinalChordToGKOSref
	;FIRST convert finalchord to GKOSref
	;This code allows accessing a table anywhere in program memory

	movf	finalchord,W
	movwf	Temp

	movlw	LOW Table_ChordToRef	;Get low 8 bits of address
	addwf	Temp,F			;Offset, do an 8-bit add operation
	movlw	HIGH Table_ChordToRef	;get high 5 bits of address
	btfsc	STATUS,C		;Page crossed?
	addlw	1			;Yes. Then increment high address
	movwf	PCLATH			;load high address in latch
	movf	Temp,W		;load computed Offset in W reg
	call	Table_ChordToRef	;call table on another Page
	movwf	GKOSref			;returning with value in W, save it as GKOSref
				;calling Table on Page 3
	movlw	HIGH FinalChordToGKOSref ;Make sure PCLATH is pointing to this Page (0)
	movwf	PCLATH
	return

GKOSrefToScPointer
	;THEN convert the GKOSref to scpointer
	;This code allows accessing a table anywhere in program memory
	movlw	LOW Table_GKOSrefToScPointer	;Get low 8 bits of address
	addwf	GKOSrefshift,F		;Offset, do an 8-bit add operation
	movlw	HIGH Table_GKOSrefToScPointer	;get high 5 bits of address
	btfsc	STATUS,C		;Page crossed?
	addlw	1			;Yes. Then increment high address
	movwf	PCLATH			;load high address in latch
	movf	GKOSrefshift,W		;load computed Offset in W reg
	call	Table_GKOSrefToScPointer ;call table on another Page
	movwf	scpointer		;save scpointer
				;calling FIN/SWE version Table on Page 3
	movlw	HIGH ScPointerToScancode ;Make sure PCLATH is pointing to this Page (0)
	movwf	PCLATH
	return

US_GKOSrefToScPointer
	;THEN convert the GKOSref to scpointer
	;This code allows accessing a table anywhere in program memory
	movlw	LOW US_Table_GKOSrefToScPointer	;Get low 8 bits of address
	addwf	GKOSrefshift,F		;Offset, do an 8-bit add operation
	movlw	HIGH US_Table_GKOSrefToScPointer	;get high 5 bits of address
	btfsc	STATUS,C		;Page crossed?
	addlw	1			;Yes. Then increment high address
	movwf	PCLATH			;load high address in latch
	movf	GKOSrefshift,W		;load computed Offset in W reg
	call	US_Table_GKOSrefToScPointer ;call table on another Page
	movwf	scpointer		;save scpointer
				;calling US version of Table on Page 3
	movlw	HIGH ScPointerToScancode ;Make sure PCLATH is pointing to this Page (0)
	movwf	PCLATH
	return


ScPointerToScancode
	;LAST convert the scpointer to Scan Code
	;This code allows accessing a table anywhere in program memory
	movlw	LOW Table_ScanCodes_abc	;Get low 8 bits of address
	addwf	scpointer,F		;Offset, do an 8-bit add operation
	movlw	HIGH Table_ScanCodes_abc	;get high 5 bits of address
	btfsc	STATUS,C		;Page crossed?
	addlw	1			;Yes. Then increment high address
	movwf	PCLATH			;load high address in latch
	movf	scpointer,W		;load computed Offset in W reg
	addlw	0x01		;add 1 to shift one step scpointer: 0...->1...
				;else will stick to first line of subroutine (Table)
	call	Table_ScanCodes_abc
	movwf	scancode		;store scancode
				;calling Table on Page 3
	movlw	HIGH ScPointerToScancode ;Make sure PCLATH is pointing to this Page (0)
	movwf	PCLATH
	return



	; ******************* SHIFTs PRESSED ******************
;-----sub------
	; Only FIN/SWE and US/UK modes can be selected
AltModes
	btfsc	MODE123on	; return if this is set
	return
	btfsc	SYMBon		; return if this is set
	return
	btfsc	CTRLon		; return if this is set
	return
	bcf	PASTEon
	bcf	ALTon		; Forget ALT

	btfss	US_version	; US/UK mode already on?
	goto	AltModes_1	; No. Turn it on.
	bcf	US_version	; Yes. Back to FIN/SWE mode.
	return
AltModes_1
	bsf	US_version	; Set US/UK mode
	return
;--------------
abc123Pressed			;bit0
	btfsc	ALTon		;Alt on?
	goto	AltModes	;Alternative modes...

	;btfss	CTRLon		;Ctrl on?
	;goto	Braille mode...

	;btfss	SYMBon		;Symb on?
	;goto	<reserved for.....>

	btfss	SHIFTon		;SHIFT on?
	goto	abc123Pressed_a
	btfsc	SHIFTlock	;But not SHIFT LOCK?
	goto	abc123Pressed_a
			;Yes. *** START KBDasMOUSE OPERATION ***
	bcf	SHIFTon		;Clear SHIFT
	bcf	PASTEon		;Clear pasting also
	bsf	KBDasMOUSE 	;Flag 'Keyboard as Mouse' operation
	return 	;goto	MainLoop
abc123Pressed_a
	btfss	MODE123on	;123mode already on?
	goto	Setabc123	;No, set it.
	bcf	MODE123on	;Yes, so clear it 123-abc=>0
	bsf	ABC123_LED		; Turn GKOS 123 LED OFF
	return	; goto	MainLoop	;
Setabc123
	bsf	MODE123on
	bcf	ABC123_LED		; Turn GKOS 123 LED ON
	return	; goto	MainLoop

MenuPressed
	call	ClearModes
	goto	SendMenuKey
;---
SymbPressed			;bits2&1 10 / 11(LOCKED)
	btfsc	ALTon		;Alt on?
	goto	WinKeyPressed	;Yes. System menu.
				; bit4/bit3: SHIFT, 10=SHIFTon, 11=SHIFTlock
	btfss	SHIFTon		;SHIFT on?
	goto	SymbPressed_a
	btfsc	SHIFTlock	;But not SHIFT LOCK?
	goto	SymbPressed_a
	goto	MenuPressed	;Yes, application menu.	

SymbPressed_a
	btfss	SYMBon		;Symb already on?
	goto	SetSymb		;No, set it.
				;
	btfss	SYMBlock	;Yes, Symb is on but is it LOCKED?. (11?)
	goto	LockSymb	;It is not LOCKED. Go lock it. (01->11)
	bcf	SYMBon		;Yes, LOCKED. Clear both Symb bits =>00
	bsf	SYMB_LED	; Turn GKOS SYMB LED OFF
	bcf	SYMBlock	;
	return	; goto	MainLoop	;(no need to send anything)
SetSymb
	bsf	SYMBon
	bcf	SYMB_LED	; Turn GKOS SYMB LED ON
	return	; goto	MainLoop
LockSymb
	bsf	SYMBlock
	return	; goto	MainLoop

WinKeyPressed
	call	ClearModes
	goto	SendWinKey
;---
ShiftPressed
				;SHIFT: bits4&3 10 / 11
	btfsc	SHIFTlock	;SHIFT LOCK ON?
	goto	ClearShiftLock	;Yes. Clear SHIFT LOCK.

	btfsc	PASTEon		;Was Pasting on?
	goto	ClearShift	;Yes. Clear SHIFT.

	btfss	SHIFTon		;No. Shift already on? (x1?)
	goto	SetShift	;No (x0), set it.
				;
	bsf	SHIFTon		;Yes. Set SHIFT LOCK.
	bsf	SHIFTlock
	bcf	CAPS_LED	; Turn GKOS CAPS LED ON
	call	SendCapsMake
		; Note that here inbetween, the LEDs will be turned on.
	call	ByteIn		; receive LED order
	call	SendACK
	call	ByteIn		; receive LED status byte
	call	SendACK

	call	SendCapsBreak

	;call	SendShiftMake	;corresponds to press and release SHIFT key
	;call 	SendShiftBreak	;send just Shift here

	return	; goto	MainLoop

ClearShift
	bcf	PASTEon		;Clear pasting also!
	bcf	SHIFTon
	bcf	SHIFTlock
	bsf	CAPS_LED	; Turn GKOS CAPS LED OFF
	return	; goto	MainLoop
ClearShiftLock
	bsf	CAPS_LED	; Turn GKOS CAPS LED OFF
	call	SendCapsMake
		; Note that here inbetween, the LEDs will be turned off.
	call	ByteIn		; receive LED order
	call	SendACK
	call	ByteIn		; receive LED status byte
	call	SendACK

	call	SendCapsBreak
	bcf	SHIFTon
	bcf	SHIFTlock
	bsf	CAPS_LED	; Turn GKOS CAPS LED OFF
	return	; goto	MainLoop

SetShift
	bsf	SHIFTon
	return	; goto	MainLoop

;---
CtrlPressed			;bit5
	btfss	CTRLon		;Ctrl on?
	goto	SetCtrl		;No, set it.
	bcf	CTRLon		;Yes, so clear it Ctrl=>00
	call	SendCtrlMake	;corresponds to press and release Ctrl key
	call	SendCtrlBreak	;SEND Ctrl here
	return	; goto	MainLoop	;
SetCtrl
	bsf	CTRLon
	return	; goto	MainLoop
;---
AltPressed			;bit6
	btfss	ALTon		;Alt on?
	goto	SetAlt		;No, set it.
	bcf	ALTon		;Yes, so clear it Alt=>0
	call	SendAltMake	;correponds to pres and release Alt key
	call	SendAltBreak	;SEND Alt
	return	; goto	MainLoop	;
SetAlt
	bsf	ALTon
	return	; goto	MainLoop

	; bit0: abc-123 1=123, 0=abc
	; bit2/bit1: SYMB,  10=SYMBon,  11=SYMBlock
	; bit4/bit3: SHIFT, 10=SHIFTon, 11=SHIFTlock
	; bit5: CTRL, 1=CTRLon - bit6: ALT, 1=ALTon  
	; bit7: Used for Paste On (it was reserved for CAPSLOCK or NUMLOCK)
ClearModes
	;clrf	GKOSmode
	bcf	CTRLon		;Always clear CTRL
	bcf	ALTon		;Always clear ALT
	btfss	SYMBlock 	;SYMBlock on?
	bcf	SYMBon		;No.
	bsf	SYMB_LED	; Turn GKOS SYMB LED OFF 
	btfsc	SHIFTlock	;SHIFT lock on?
	return			;Yes. Continue and leave SHIFT LOCK on.
		;No. Clear SHIFT unless arrows/words/PgUp&PgDn (pasting)

	btfss	SHIFTon		;..but is SHIFT on?!
	return			;No. Might return as well...
				;Yes SHIFT is ON:

	;GKOSref: 42...53 are navigating except 50 and 46 (=space, backsp)

	;PASTE function
	movlw	d'42'		;Test if GKOSref is lower than 42 
	subwf	GKOSref,W	;GKOSref - 42
	btfss	STATUS,C	;Note: C = complement of Borrow
	goto	ClearModesX_C	;Yes, lower, clear SHIFT and exit
				;No. not lower, might be pasting.
	movf	GKOSref,W	;Test if higher than 53
	sublw	d'53'		; 53 - W (=GKOSref)
	btfss	STATUS,C	;Note: C = complement of Borrow
	goto	ClearModesX_C	;Yes, higher, clear SHIFT and exit
	
			;test if 50 or 46
	movlw	d'50'
	xorwf	GKOSref,W
	btfsc	STATUS,Z	;equal?
	goto	ClearModesX_C	;yes, exit and clear SHIFT

	movlw	d'46'
	xorwf	GKOSref,W
	btfsc	STATUS,Z	;equal?
	goto	ClearModesX_C	;yes, exit and clear SHIFT
				;leave SHIFT ON (pasting)
	bsf	PASTEon		;Yes. Leave SHIFT ON. Set Pasting on. Paste.
	return
ClearModesX_C
	bcf	SHIFTon		;Clear SHIFT if not pasting	
	return
;--------------------------------------------------------------


	; bit0: abc-123 1=123, 0=abc
	; bit2/bit1: SYMB,  10=SYMBon,  11=SYMBlock
	; bit4/bit3: SHIFT, 10=SHIFTon, 11=SHIFTlock
	; bit5: CTRL, 1=CTRLon - bit6: ALT, 1=ALTon  
	; bit7: Used for Paste On (it was reserved for CAPSLOCK or NUMLOCK)

;********** Call these before and after each key-press:

CheckMakes
	btfsc	CTRLon		;Send Ctrl Make?
	call	SendCtrlMake	;Yes.
	btfsc	ALTon		;Send Alt Make?
	call	SendAltMake	;Yes.
	btfsc	SHIFTlock	;SHIFT Lock on?
	return			;yes. No Shift sent
	btfss	SHIFTon		;Send Shift Make?
	return			;No.
				;Yes, but not in 123 mode 
	btfsc	MODE123on		;bit0=1?(123 mode?)
	return			;Yes. Send no Shift.
				;No. This may be abc mode, continue.
	btfsc	SYMBon		;bit2=1?(SYMB mode?)
	return			;Yes. Send no Shift.
				;No. This is abc mode, continue
	call	SendShiftMake	;send
	return
CheckBreaks
	btfsc	CTRLon		;Send Ctrl Break?
	call	SendCtrlBreak	;Yes.
	btfsc	ALTon		;Send Alt Break?
	call	SendAltBreak	;Yes.
	btfsc	SHIFTlock	;SHIFT Lock on?
	return			;yes. No Shift sent
	btfss	SHIFTon		;Send Shift Break?
	return			;No.
				;Yes, but not in 123 mode 
	btfsc	MODE123on	;bit0=1?(123 mode?)
	return			;Yes. Send no Shift.
				;No. This may be abc mode, continue.
	btfsc	SYMBon		;bit2=1?(SYMB mode?)
	return			;Yes. Send no Shift.
				;No. This is abc mode, continue.
	call	SendShiftBreak	;Send
	return

;***************** CALL THESE TO SEND SHIFT KEYS **********************'

SendShiftMake
	;btfsc	AutoRepeat	;Ignore Typematic
	;return
	movlw	0x59 		;(Right) Shift - Make SHIFT
	call	ByteOut
	return
SendShiftBreak
	;btfsc	AutoRepeat	;Ignore Typematic
	;return
	movlw	0xf0 		;(Right) Shift - Break SHIFT
	call	ByteOut
	movlw	0x59 		;
	call	ByteOut
	return
;*******************
SendCapsMake
	btfsc	AutoRepeat	;Ignore Typematic
	return
	movlw	0x58 		;Make CAPS LOCK
	call	ByteOut
;SendCapsMake_aa
;	Delay	50		;Wait for CAPS LOCK LED order and settings from host.
;	btfsc	DATA		;Is DATA pulled low by Host?
;	goto 	SendCapsMake_a	;No.
;	call	ByteIn		;Yes. Receive one byte into RECEIVE register.
;	call	SendAck		;Acknowledge it by default.
;	goto	SendCapsMake_aa
;SendCapsMake_a
	return
SendCapsBreak
	btfsc	AutoRepeat	;Ignore Typematic
	return
	movlw	0xf0 		;Break CAPS LOCK
	call	ByteOut
	movlw	0x58 		;
	call	ByteOut
	return
;*******************
SendAltMake
	movlw	0x11 		;Alt - Make ALT
	call	ByteOut
	return
SendAltBreak
	movlw	0xf0 		;Alt - Break ALT
	call	ByteOut
	movlw	0x11 		;
	call	ByteOut
	return
;*******************
SendCtrlMake
	movlw	0x14 		;(Left) Ctrl - Make CTRL
	call	ByteOut
	return
SendCtrlBreak
	movlw	0xf0 		;(Left) Ctrl - Break CTRL
	call	ByteOut
	movlw	0x14 		;
	call	ByteOut
	return
;*******************
SendAltGrMake
	movlw	0xe0 		;Alt Gr - Make ALT GR
	call	ByteOut
	movlw	0x11
	call	ByteOut
	return
SendAltGrBreak
	movlw	0xe0 		;Alt Gr - Break ALT GR
	call	ByteOut
	movlw	0xf0
	call	ByteOut
	movlw	0x11 		;
	call	ByteOut
	return

;******************* ROUTINES TO SEND DIFFERENT TYPES OF SCAN CODES ******************

;One-byte scan codes
;-------------------

SendCode_basic
	call	CheckMakes	;send Make codes for any shifts on

	movf	sc_buffer0,W	;In this basic case, the first byte in sc_buffer is sent	
	call	ByteOut		;sending Make code  0xyy
	movlw	0xf0		;sending Break code 0xf0 0xyy
	call	ByteOut		;
	movf	sc_buffer0,W	;
	call	ByteOut		;

	call	CheckBreaks	;Send Break codes for any shifts on
	btfss	AutoRepeat	; If autorepeat is on, skip clearing modes
	call	ClearModes
	return	; goto	MainLoop	;What next?

;Two-byte scan codes
;-------------------

SendCode_basic2	
	call	CheckMakes	;send Make codes for any shifts on

	incf	scpointer,F	;Scan code pointer + 1
	call	ScPointerToScancode  ;Get the corresponding second scan code 
				;returning with next scan code in scancode
	movf	scancode,W
	movwf	sc_buffer1	;save the scancode in W and sc_buffer1

	movlw	0xe0		;get the first byte of Make code
	call	ByteOut		;...sending Make code  0xe0 0xyy
	movf	sc_buffer1,W	;get the second byte of Make code
	call	ByteOut		;
				;
	movlw	0xe0		;Start sending Break code 0xe0 0xf0 0xyy
	call	ByteOut		;
	movlw	0xf0		;
	call	ByteOut
	movf	sc_buffer1,W	;
	call	ByteOut		;

	call	CheckBreaks	;Send Break codes for any shifts on
	btfss	AutoRepeat	; If autorepeat is on, skip clearing modes
	call	ClearModes
	return	; goto	MainLoop	;What next?

;Special keys
;------------

SendPause
	movlw	0xe1	;Make (there is no Brake code)
	call	ByteOut	
	movlw	0x14
	call	ByteOut	
	movlw	0x77
	call	ByteOut	
	movlw	0xe1
	call	ByteOut	
	movlw	0xf0
	call	ByteOut	
	movlw	0x14
	call	ByteOut	
	movlw	0xf0
	call	ByteOut	
	movlw	0x77
	call	ByteOut	
	btfss	AutoRepeat	; If autorepeat is on, skip clearing modes
	call	ClearModes
	return	; goto	MainLoop	;What next?

SendPrintScreen
	movlw	0xe0	;Make
	call	ByteOut	
	movlw	0x12
	call	ByteOut	
	movlw	0xe0
	call	ByteOut	
	movlw	0x7c
	call	ByteOut	
	movlw	0xe0	;Break
	call	ByteOut	
	movlw	0xf0
	call	ByteOut	
	movlw	0x7c
	call	ByteOut	
	movlw	0xe0
	call	ByteOut	
	movlw	0xf0
	call	ByteOut	
	movlw	0x12
	call	ByteOut	
	btfss	AutoRepeat	; If autorepeat is on, skip clearing modes
	call	ClearModes
	return	; goto	MainLoop	;What next?

;Send Scan Code with Shift
;-------------------------

SendCode_Shift
	movlw	0x59 		;(Right) Shift - Make SHIFT
	call	ByteOut
	incf	scpointer,F		;point to next byte of scan code
	call	ScPointerToScancode   	;Get the scan code pointed at,
					;-> saved in: scancode				    
	movf	scancode,W	;get the second scancode in W for sending - Make
	call	ByteOut		;Send second byte in sc table (first was not sent)
	movlw	0xf0		;Break
	call	ByteOut
	movf	scancode,W
	call	ByteOut

	movlw	0xf0 		;(Right) Shift - Break SHIFT
	call	ByteOut
	movlw	0x59 		;
	call	ByteOut
	btfss	AutoRepeat	; If autorepeat is on, skip clearing modes
	call	ClearModes
	return	; goto	MainLoop	;What next?

;Send Scan Code with Alt Gr
;--------------------------

SendCode_AltGr
	movlw	0xe0		;Alt Gr down = 0xe0 0x11 **Make** 
	call	ByteOut
	movlw	0x11 		;
	call	ByteOut		;...

	incf	scpointer,F		;point to next byte of scan code
	call	ScPointerToScancode   	;Get the scan code pointed at,
					;-> saved in: scancode				    
	movf	scancode,W	;get the second scancode in W for sending - *Make*
	call	ByteOut		;Send second byte in sc table (first was not sent)
	movlw	0xf0		;*Break*
	call	ByteOut
	movf	scancode,W
	call	ByteOut

	movlw	0xe0		;Alt Gr up 0xe0 0xf0 0x11 **Break**
	call	ByteOut
	movlw	0xf0 		;
	call	ByteOut
	movlw	0x11 		;...
	call	ByteOut
	btfss	AutoRepeat	; If autorepeat is on, skip clearing modes
	call	ClearModes
	return	; goto	MainLoop	;What next?
SendWordLeft
	call	CheckMakes
	call	SendCtrlMake	;Ctrl Make
	movlw	0xe0		;Left Arrow Make 
	call	ByteOut
	movlw	0x6b
	call	ByteOut
	movlw	0xe0		;Left Arrow Break 
	call	ByteOut
	movlw	0xf0
	call	ByteOut
	movlw	0x6b
	call	ByteOut
	call	SendCtrlBreak	;Ctrl Break
	call	CheckBreaks
	btfss	AutoRepeat	; If autorepeat is on, skip clearing modes
	call	ClearModes
	return	; goto	MainLoop	;What next?
SendWordRight
	call	CheckMakes
	call	SendCtrlMake
	movlw	0xe0		;Right Arrow Make 
	call	ByteOut
	movlw	0x74
	call	ByteOut
	movlw	0xe0		;Right Arrow Break 
	call	ByteOut
	movlw	0xf0
	call	ByteOut
	movlw	0x74
	call	ByteOut
	call	SendCtrlBreak
	btfss	AutoRepeat	; If autorepeat is on, skip clearing modes
	call	ClearModes
	call	CheckBreaks
	return	; goto	MainLoop	;What next?

SendWinKey
	movlw	0xe0	;Make
	call	ByteOut	
	movlw	0x1f
	call	ByteOut	
	movlw	0xe0	;Break
	call	ByteOut	
	movlw	0xf0
	call	ByteOut	
	movlw	0x1f
	call	ByteOut	
	return	; goto	MainLoop

SendMenuKey
	movlw	0xe0	;Make
	call	ByteOut	
	movlw	0x2f
	call	ByteOut	
	movlw	0xe0	;Break
	call	ByteOut	
	movlw	0xf0
	call	ByteOut	
	movlw	0x2f
	call	ByteOut	
	return	; goto	MainLoop

;	    retlw	 0xe0 ;left Flying Window	
;	    retlw	 0x1f ;	110
;	    retlw	 0xe0 ;right Flying Window	
;	    retlw	 0x27 ;	
;	    retlw	 0xe0 ;Pop Up Menu	
;	    retlw	 0x2f ; 114

;=====================================================================================





;--------------------------------------------------------------

PS2SendMov	; W = 0x02 POINTER MOVEMENT IR data received (bit1=1)
	;movlw	d'2'		;debug
	;call	SerTx		;


	btfss	M_ENABLE	; Is Host ready to receive mouse data? (=ENABLE sent by the Host?)
	;goto	MainLoop	; No.
	goto	MBAT		; No. Do the Mouse BAT (0.5 sec) then.
				; Yes.


	; Build MouseByte1 for sending to the host:

; IRByte1:    -    -    Yovf  Xovf  Ysign Xsign   RButton  LButton  (Received from IR)
; MouseByte1: Yovl Xovl Ysign Xsign  '1'  MButton RButton  LButton  (To send to PS/2)

	movf	IRByte1,W	; Get IRByte1 into TEMPX for actions
	movwf	TEMPX
	movlw	b'00001000'	; First, set the 'Allways 1'
	movwf	MouseByte1	;                      0 0 0 0  1 0 0 0
	movf	TEMPX,W		; Second, move RButton and LButton bits
	andlw	b'00000011'	; clear the rest       0 0 0 0  0 0 b b
	addwf	MouseByte1,F	; and add the two bits 0 0 0 0  1 0 b b
	rlf	TEMPX,F		; Next, Yovf  Xovf Ysign Xsign
	rlf	TEMPX,F		;                      y x y x  b b 0 0
	movf	TEMPX,W
	andlw	b'11110000'	;                   W: y x y x  0 0 0 0
	addwf	MouseByte1,F	;          MouseByte1: y x y x  1 0 b b


	;movf	MouseByte1,W	;debug
	;call	SerTx		;debug

	; Send the Mouse data packet to PS/2

	movf	MouseByte1,W	; Buttons pressed etc
	call	MByteOut
	movf	IRByte3,W	; X movement data
	call	MByteOut
	movf	IRByte4,W	; Y movement data
	call	MByteOut

	goto	MainLoop


;--------------------------------------------------------------

PS2SendScroll	; W = 0x04 SCROLL WHEEL IR data received (bit2=1)
	movlw	d'3'		;debug
	call	SerTx		;

	btfss	M_ENABLE	; Is Host ready to receive mouse data? (=ENABLE sent by the Host?)
	return			; No.
				; Yes.

;   ----- MORE CODE HERE.....

	return

;**********************************************************************
;(Acknowledge every byte received)
;SendAck
SendACK
	movlw	0xfa
	call	ByteOut
	return
MSendAck
	movlw	0xfa
	call	MByteOut
	return
;----------------------
;(BAT = Basic Assurance Test)
SendBAT
	movlw	0xaa	;BAT successful
	call	ByteOut
	return
MSendBAT	;
	movlw	0xaa	;BAT successful
	call	MByteOut
	movlw	0x00	;MouseID
	call	MByteOut
	return
;----------------------
MSendBATfailed
	movlw	0xfc
	call	MByteOut
	return
SendBATfailed
	movlw	0xfc
	call	ByteOut
	return
;----------------------
;Respond to 0xF2 (Read ID)
;First Ack, then this:
MSendID
	movlw	0x00
	call	MByteOut	
	return
SendID
	movlw	0xab
	call	ByteOut
	; send also next byte always? 2005 XP problems
	movlw	0x83
	call	ByteOut
	return
;---------------------
SendEcho
	movlw	0xee
	call	ByteOut
	return
;-------------
MSendEcho
	movlw	0xee
	call	MByteOut
	return

;----------------------
;Respond to 0xe9 (Status Request) with Mouse Status (3 bytes of mouse data)
;First Ack, then this: 0x00 0x02 0x64
MSendStatus	;as a response to status request
	movlw	0x00	;< Mode=0(stream), Enable=0(no data reporting), Scaling=0(1:1),
	call	MByteOut	;  No buttons pressed
	movlw	0x02	;< Resolution=2 (4 counts/mm)
	call	MByteOut
	movlw	0x64	;< Sample rate (100 samples/sec.) 0x64=d'100'
	call	MByteOut
	return 
;*********************

;**********************************************************************
CheckIR
	btfsc	IRDATA		; IR Pulse there? TEST FOR ANY IR PULSE
	goto	CheckIRX	; No. Exit.
	call	ReadIRstart	; Yes. Is it a Start pulse?
	xorlw	0x00		; Start pulse ok?
	bnz	CheckIRX	; No. Exit.

	clrf	IRByte1		; Yes. Clear the first IR byte buffer
	call	ReadIR6bits	; Receive 6 bits: --54 3210 (D5...D0)
	xorlw	0x00		; 6 bits received ok?
	bnz	CheckIRX	; No. Exit.

	movf	TEMPX,w		; Yes. Save value. === IRByte1 ===
	movwf	IRByte1		;
	clrf	IRByte2		; Clear rest of the IR byte buffers
	clrf	IRByte3
	clrf	IRByte4
	call	ReadIR5bits	; Receive 5 bits: xxxa aadg (A2 A1 A0 1/0 toggle) 1=chord
	xorlw	0x00		; 5 bits received ok?
	bnz	CheckIRX	; No. Exit.
				
	movf	TEMPX,w		; Yes. Save value. === IRByte2 ===
	movwf	IRByte2		; (if 1/0 = 0, continue receiving mouse packet)
				; While IRByte2 still in W, check if device info is correct.
	andlw	b'00011100'	; 000a aa00 = 0001 1100? in IRByte2
	xorwf	IRdevice,w	; (IRdevice = 0001 1100)
	bnz	CheckIRX

	btfss	IRByte2,1	; bit1=1? (1=chord)	
	goto	CheckIRMouse	; No. Continue by receiving mouse packet data.

				; Yes. Chord value has been received OK.
	movf	IRByte1,W	; Save Chord in param. RXchord
	movwf	RXchord		;
	;call	ShowIRpackets	;debug

	retlw	0x01		; CHORD value received OK EXIT => bit0=1



CheckIRMouse
				; Two extra bits A3 and Z are received here for deciding 
				; whether XY movement (Z=0) or wheel data (Z=1)follows
	call	ReadIRbit	; Read bit A3 (for future use)
	btfsc	tempflags,0	; Error in bit reception?
	goto	CheckIRX	; Yes. IR bit error ***
	call	ReadIRbit	; Read bit Z (0/1 = movement/wheel data indication)
	btfsc	tempflags,0	; Error in bit reception?
	goto	CheckIRX	; Yes. IR bit error ***

				;'1' => 1000 0000 in W (0x80) scroll wheel
				;'0' => 0000 0000 in W (0x00) movement

	xorlw	0x80		; Decide on movement or scroll wheel reception
	bz	CheckIRscroll

	; Receive Movement data
	; =====================

	call	ReadIR8bits	; Receive 8 bits. X movement data.
	xorlw	0x00		; 8 bits received ok?
	bnz	CheckIRX	; No. Exit.
	movf	TEMPX,w		; Yes. Save value. === IRByte3 ===
	movwf	IRByte3		;

	call	ReadIR8bits	; Receive 8 bits. Y movement data.
	xorlw	0x00		; 8 bits received ok?
	bnz	CheckIRX	; No. Exit.
	movf	TEMPX,w		; Yes. Save value. === IRByte4 ===
	movwf	IRByte4		;

CheckIRmovOK
	;call	ShowIRpackets	;debug
	retlw	0x02		; MOVEMENT data received OK EXIT => bit1=1


	; Receive Scroll Wheel Data
	; =========================

CheckIRscroll
	call	ReadIR8bits	; Receive 8 bits. Wheel data.
	xorlw	0x00		; 8 bits received ok?
	bnz	CheckIRX	; No. Exit.
	movf	TEMPX,w		; Yes. Save value. === IRByte3 ===
	movwf	IRByte3		;
	call	ShowIRpackets	;debug
	retlw	0x04		; SCROLL WHEEL data received OK EXIT. bit2=1

CheckIRX
	retlw	0x80		;IR reception UNSUCCESSFUL EXIT => bit7=1



;======================= GKOS & Mouse SUBROUTINES ======================




;-----
			; WIRED GKOS SCANNING
			; ===================

ReadGKOSchord			;-LATEST KEY POLLING ROUTINE- 4/2004
				; This can use the same enhanced chord
				; detection routines as with IR reception

	clrf	maxchord	; Default: no chord
	clrf	RXchord		; Default: no chord
	bcf	GKOSstatus,0	; Default: chord received indicator bit0 = 0

	decfsz	GKOScounter1	; Too soon to re-scan?
	return			; Yes, no scan yet.
	movlw	GKOSdelay	; No. It may be time to scan.
	movwf	GKOScounter1	; Initialize counter.	

	decfsz	GKOScounter2	; Too soon to re-scan?
	return			; Yes, no scan yet.
	movlw	GKOSdelay	; No. It's be time to scan now.
	movwf	GKOScounter2	; Initialize counter.	


;----- NEW CODE to use the same key polling procedure as with IR reception


	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
	movwf	maxchord	; save chord for re-check
	movlw	0x00		; Is it zero (no keys down at the moment)
	xorwf	chord,W		;
	btfss	STATUS,Z	; chord equal to 0? 
	goto	ReadGKOSchord_1	; No.
				; Yes.

	; Send 5 zero chords after release of keys due to enhanced key polling

	incf	ZeroChords,f	; Zero Chord counter (5...0)
	decfsz	ZeroChords,f	; was it zero already?
	btfsc	STATUS,Z	; ZeroChord counter Equal to 0?
	return			; Yes. Exit right away. All GKOS keys are up.
				; No.
	;bcf	TextOnly	; Allow all characters next.
	decf	ZeroChords,f	; Decrement counter and send a Zero Chord.
	goto	ReadGKOSchord_1b

	; Non-zero chord value received

ReadGKOSchord_1

	movlw	d'5'		; Initialize Zero Chord counter
	movwf	ZeroChords	; when non-zero chords are detected

ReadGKOSchord_1b 
	movf	chord,w
	movwf	RXchord		; Save the chord as parameter RXchord
	bsf	GKOSstatus,0	; Chord received indicator bit0 = 1
	return


;------------------------------------------------------------------------------

		; IR RECEPTION
		; ============

ReadIRstart		;Sony Format (SIRCS)
		;IR data formats.  SIRC spec: 01111 = MD
		;MD 0001000 11110 / GKOS: 000100 01111(0) = cccccc gdaaa(0) <on oscilloscope
		;MD: 7 + 5 bits / GKOS: 6 + 5 bits. Received byte order: xxxa aadg
		;      
		;__   if a continuous pulse lasts 1,6 ms it should be a start pulse
	bcf	TESTPOINT	;--TP: IR burst (low)
	;bcf	GKOSstatus,0	;indicate no chord received as a deafault
	bcf	GKOSstatus,6	;Flag: No packet received yet. Pulse = line low. (NOT USED)
				;Is this the START PULSE of 2200us (1.1ms - 2.2ms) 1.65ms
	movlw	d'16'		;Number of 100us loops
	movwf	temp_a		;Set counter. 16 x 103us = 1.648ms
ReadIRstart_a
	btfsc	IRDATA		;Pulse still there? TEST START PULSE	-   1us -
	retlw	0xEE		;No. UNSUCCESSFUL RETURN W=0xEE ******
	Delay	d'100'		;Delay of 100us (16 x 100us = 1.6ms)	- 100us -
	decfsz	temp_a,f	;Counter=0?					-   1us -
	goto	ReadIRstart_a	;No.						-   1us - (103us)
				;Yes. Pulse length was at least 1.6 ms (IR START PULSE).
				;Information part: 	'1'= 0.55ms high + 1.1 ms low
				;			'0'= 0.55ms high + 0.55ms low
				;Wait for a pulse > Check at 0.825ms: high=>'0', low=>'1'
				;then wait for no pulse (high) and again for a pulse,
				;7 bits (chord value) + 5 bits (device = 00010, Betamax)
;(Timing: 275/550/825/1100)
;          ___
;_________/	  pulse =0 / no pulse =1
;      ^

ReadIRstart_b			;=Wait for no pulse=
	btfss	IRDATA		;Low? (=pulse?)
	goto	ReadIRstart_b	;Yes. Still wait... PULL-UPs required else FREEZING HERE
				;No. The Start Pulse has reached the end. Line is high.
;          ___     _____
;_________/   \___/___\_ pulse =0 / no pulse =1
;          ^   |--first bit

	Delay	d'275'		; Wait until middle of the first gap to match timing ahead
	bsf	TESTPOINT	;--TP: high (no burst)

;          ___     _____
;_________/   \___/___\_ pulse =0 / no pulse =1
;           ^  |--first bit

	retlw	0x00		;SUCCESSFUL RETURN W=0x00 ******
;-------------------

;---IR Receive 8 bits

ReadIR8bits
	clrf	TEMPX		;Clear register for byte reception
	movlw	d'8'		;Set Counter (temp_b) to 6 (bits), GKOS Chord value
	movwf	temp_b
ReadIR8bits_a
	rrf	TEMPX,f		;rotate right
	bcf	TEMPX,7		;Make sure bit7=0

	call	ReadIRbit	;Read one bit into W (b000 0000)
	btfsc	tempflags,0	;Error in bit reception?
	retlw	0xEE		;Yes.   *** ERROR RETURN W=0xEE ***
	addwf	TEMPX,f		;No, add the received bit to the byte

	decfsz	temp_b,f	;All 8 bits received?
	goto	ReadIR8bits_a	;No.
				;Yes.
	movf	TEMPX,w		;
	  ;movf	   TEMPX,w	;debug
	  ;call	   SerTx	;debug
	retlw	0x00		;SUCCESSFUL RETURN W=0x00, bits in TEMPX: 7654 3210
;--------

;--IR receive 7 bits

ReadIR7bits
	clrf	TEMPX		;Clear register for byte reception
	movlw	d'7'		;Set Counter (temp_b) to 7 (bits), GKOS Chord value
	movwf	temp_b
ReadIR7bits_a
	call	ReadIRbit	;Read one bit into W (b000 0000)
	btfsc	tempflags,0	;Error in bit reception?
	retlw	0xEE		;Yes.  *** ERROR RETURN W=0xEE ***
	addwf	TEMPX,f		;No, add the received bit to the byte
	rrf	TEMPX,f		;rotate right
	bcf	TEMPX,7		;Make sure bit7=0
	decfsz	temp_b,f	;All 7 bits received?
	goto	ReadIR7bits_a	;No.
				;Yes. 
	movf	TEMPX,w		;
	  ;movf	   TEMPX,w	;debug
	  ;call	   SerTx	;debug
	retlw	0x00		;SUCCESSFUL RETURN W=0x00, bits in TEMPX: -654 3210
;-------

;---IR Receive 6 bits

ReadIR6bits
	clrf	TEMPX		;Clear register for byte reception
	movlw	d'6'		;Set Counter (temp_b) to 6 (bits), GKOS Chord value
	movwf	temp_b
ReadIR6bits_a
	call	ReadIRbit	;Read one bit into W (b000 0000)
	btfsc	tempflags,0	;Error in bit reception?
	retlw	0xEE		;Yes.  *** ERROR RETURN W=0xEE ***
	addwf	TEMPX,f		;No, add the received bit to the byte
	rrf	TEMPX,f		;rotate right
	bcf	TEMPX,7		;Make sure bit7=0
	decfsz	temp_b,f	;All 6 bits received?
	goto	ReadIR6bits_a	;No.
				;Yes. One more shift (6 bits of data)
	rrf	TEMPX,f		;rotate right
	bcf	TEMPX,7		;Make sure bit7=0
	movf	TEMPX,w		;
	  ;movf	   TEMPX,w	;debug
	  ;call	   SerTx	;debug
	retlw	0x00		;SUCCESSFUL RETURN W=0x00, bits in TEMPX: --54 3210
;-------

;---IR Receive 5 bits

ReadIR5bits
	;Receive the Toggle bit G (=D7) and Device information part correctly
	clrf	TEMPX		;Clear register for byte reception
	movlw	d'5'		;Set Counter (temp_b) to 5 (bits), Device info
	movwf	temp_b
ReadIR5bits_a	
	call	ReadIRbit	;Read one bit into W (b000 0000)
	btfsc	tempflags,0	;Error in bit reception?
	retlw	0xEE		;Yes.  *** ERROR RETURN W=0xEE ***
	addwf	TEMPX,f		;No, add the received bit to the byte
	rrf	TEMPX,f		;rotate right
	bcf	TEMPX,7		;Make sure bit7=0
	decfsz	temp_b,f	;All 5 bits received?
	goto	ReadIR5bits_a	;No.
				;Yes. Two more shifts (5 bits of data)
	rrf	TEMPX,f		;rotate right
	bcf	TEMPX,7		;Make sure bit7=0
	rrf	TEMPX,f		;rotate right
	bcf	TEMPX,7		;Make sure bit7=0
	movf	TEMPX,w		;
	  ;movf	   TEMPX,w	;debug
	  ;call	   SerTx	;debug

	retlw	0x00		;SUCCESSFUL RETURN W=0x00, bits in TEMPX: ---4 3210
;---------
;---------
ReadIRbit
	bcf	tempflags,0	;Set flag: Default = 0 = Success

;low = IR pulse, high = no IR
;    ___     ___
;___/   \___/   \___/
;       |---0---|
;    ___         ___
;___/   \_______/   \___/
;       |-----1-----|
;             ^decide here if 0 or 1
;
; Starting points:
;low = IR pulse, high = no IR
;    ___
;___/
;     ^ after Start Pulse or '0'
;    ___
;___/
; ^ after '1'


	;Make sure there is no pulse first

	; Make sure not to have to wait too long (it would be a reception error)
	; - max 375us (>275us) - (if previous bit was a '1', else it is no pulse already) 

	movlw	d'29'		;Number of 13us loops: 29 x 13us = 377us (gap = 0,550ms)
	movwf	temp_a		;Set counter to around 375us (375us/13us = 29)

ReadIRbitNP
	btfsc	IRDATA		;Pulse (line low) still there?	 1us
	goto	ReadIRbitNX	;No. No more pulse.
	Delay	d'10'		;Yes, ... loop back.			 10us
	decfsz	temp_a,f	;No. Counter=0?			 1us
	goto	ReadIRbitNP	;No.					 1us => 13us 
	bsf	tempflags,0	;Yes. Timeout. Flag the error
	return			;This is an ERROR return. No end of IR pulse found.
ReadIRbitNX

; Wait for a new pulse (low), then wait 825 us and check state (low='1', hight='0')

				;No more pulse. Line high now.
	bsf	TESTPOINT	;--TP: no burst (high)

	;movlw	d'100'		;Number of 10us loops: 100 x 10us = 1ms (gap = 0,550ms)
	movlw	d'54'		;Number of 13us loops: 54 x 13us = 702us (gap = 0,550ms)
	movwf	temp_a		;Set counter to around 700us (700us/13us = 54)
ReadIRbit_a

;low = IR pulse, high = no IR
;    ___
;___/   \_
;       ^
	; Wait for IR pulse (low) to start

	; Make sure not to have to wait too long (it would be a reception error)
	; max - 700us -

	Delay	d'10'		;Check it every 10us			 10us
	btfss	IRDATA		;Any pulse (low) appearing there?	 1us
	goto 	ReadIRbit_b	;Yes! Data bit starting...
	decfsz	temp_a,f	;No. Counter=0?			 1us
	goto	ReadIRbit_a	;No.					 1us => 13us 
	bsf	tempflags,0	;Yes. Timeout. Flag the error
	return			; This is an ERROR return. IR pulse start missing.

ReadIRbit_b

;    ___     ___
;___/   \___/___
;             ^
;       |----->
;        825us (delay counter value = 70)

	bcf	TESTPOINT	;--TP: burst (low)
	; Wait 825us and check IR data line state -----------
	movlw	d'70'		; Number of 10us's to wait (4 MHz XT OSC)
				; 70 = Oscilloscope-adjusted value using TESTPOINT
	movwf	temp_a		;Set counter	

ReadIRbit_bb
	Delay	d'10'		; Wait 10us each time	 10us
	decfsz	temp_a,f	; Counter=0? (70 => 0)	 1us + 1us
	goto	ReadIRbit_bb	; No. loop back		 70 x 12us = 840us
				; Yes.
	bsf	TESTPOINT	;--TP: no burst (high) to test reading time point
	btfss	IRDATA		; Pulse(=low) ended? => '0'
	goto	ReadIRbit_1	; No.  '1' received
	retlw	0x00		; Yes. '0' received
;    ___     ___
;___/   \___/   \___
;       |-------|
;             ^test=>'0'    (Timing: 275/550/825/1100)

ReadIRbit_1			;'1' => 1000 0000 in W (0x80)
	retlw	0x80		;'0' => 0000 0000 in W (0x00)
;    ___         ___
;___/   \_______/   \___
;       |-----------|
;             ^test=>'1'

;*********************


;---------------------------------------------------------------------------------------------
;PS/2 Keyboard Byte Transmission

ByteOut		; byte to send in W
		call 	ByteOut_start
		call 	SerTx3	; debug
		movf	TXBYTE,w
		call	SerTx4
		return


ByteOut_start		
		;bcf	TXstatus,1 ;Set default (nothing received during TX)
		movwf	TXBYTE		;Save the original byte to be sent
ByteOut_a	movwf	TXBYTEtemp	;Save the actual byte to be sent
		call	SendByte
		movwf	TEMPX	;Save return code
		xorlw	0x00	;Byte sent ok? (0x00?)
		btfsc	STATUS,Z
		goto	SendByteOK  ;Yes. Return with all OK. (0x00)
		movf	TEMPX,W
		xorlw	0xFF	;Request to send from Host? (0xff?)
		btfsc	STATUS,Z
		goto	SendByteRX  ;Yes. Receive and acknowledge.	
		movf	TEMPX,W	;Return with all other return values (0x..)
		return		;(This is due to Inhibit: 0xfe)
SendByteRX
		call	ByteIn	;RTS -> Receive
		bsf	TXstatus,1 ;set bit1 to indicate reception instead of sending.
		movlw	0xfa	;Send ACK
		goto	ByteOut_a	
		
SendByteOK	
		;retlw	0x00	;return without sending <= unsuccessful TEST for CAPS LOCK

		movf	TXBYTEtemp,W	;was the byte sent the original or just the ACK?
		xorwf	TXBYTE,W
		btfsc	STATUS,Z
		retlw	0x00	;It was the original byte to send. Return OK.
		movf	TXBYTE,W ;No. Send the Original Byte to send, too.
	retlw	0x00	; TEST by not resending !!! 1/2005 XP
		goto	ByteOut_a 	;>>in fact the keyboard should clear its send buffer
					;and NOT send the byte after receiving a command!!!

SendByte          movwf   TEMP0
		  bcf	  STATUS, RP1     ;Use Reg Banks 0-1: 0x 
		 ; btfsc	  TXstatus,0
		 ; return		;return without sending anything if bit0=1
InhibitLoop       btfss   CLOCK           ;Test for inhibit  
                  goto    InhibitLoop 
                  Delay   50 
                  btfss   CLOCK 
                  goto    InhibitLoop 
                  btfss   DATA            ;Check for request-to-send  
                  retlw   0xFF 
                  clrf    PARITY 
                  movlw   0x08 
                  movwf   COUNTER 
                  movlw   0x00   
                  call    BitOut          ;Start bit (0) 
                  btfss   CLOCK           ;Test for inhibit  
                  goto    ByteOutEnd 
                  Delay   4 
ByteOutLoop     movf    TEMP0, w 
                  xorwf   PARITY, f 
                  call    BitOut          ;Data bits 
                  btfss   CLOCK           ;Test for inhibit 
                  goto    ByteOutEnd 
                  rrf     TEMP0, f 
                  decfsz  COUNTER, f 
                  goto    ByteOutLoop 
                  Delay   2 
                  comf    PARITY, w  
                  call    BitOut          ;Parity bit 
                  btfss   CLOCK           ;Test for inhibit 
                  goto    ByteOutEnd 
                  Delay   5 
                  movlw   0xFF    
                  call    BitOut          ;Stop bit (1) 
                  Delay   48 
                  retlw   0x00 

ByteOutEnd        DATA_1
		  CLOCK_1
                  retlw   0xFE 
     
BitOut               ;bsf     STATUS, RP0 ;Bank 1
                  andlw   0x01 
                  btfss   STATUS, Z 
                  DATA_1 ;bsf     DATA ;DATA=1
                  btfsc   STATUS, Z 
                  DATA_0 ;bcf     DATA ;DATA=0
                  Delay   21 
                  CLOCK_0 ;bcf     CLOCK ;CLOCK=0
                  Delay   45 
                  CLOCK_1 ;bsf     CLOCK ;CLOCK=1
                     ;bcf     STATUS, RP0 ;Bank 0
                  Delay   5 
                  return



;*********************
;PS/2 Keyboard Byte Reception

;Every byte received from the PC must be acknowledged by 0xfa,
; except for 'Resend'(0xfe) and 'Echo'(0xee) commands.
;
;ByteIn: 
;Reads a byte from the host.  
;Result in "RECEIVE" register.
;Returns 0xFD in w if timeout.  
;Returns 0xFE in w if host aborts transmission.  
;Returns 0xFF in w if framing/parity error detected. 
;Returns 0x00 in w if byte received successfully. 

ByteIn0
		Delay		d'100'		;Timeout basic delay
		decfsz		TEMP0,f		;Timeout loops done?
		goto		ByteIn1	;No.
		retlw		0xFD		;Yes. Return and indicate timeout.

ByteIn	
	            bcf     STATUS, RP1     ;Use Reg Banks 0-1: 0x
		     movlw	d'255'		;Set Timeout counter n=255 (n x 100 us)
		     movwf	TEMP0		;Set Timeout counter n=255 (n x 100 us)
ByteIn1	     btfss   CLOCK           ;Wait for start bit 
                  goto    ByteIn0 
                  btfsc   DATA 
                  goto    ByteIn0
ByteInTEST
                  movlw   0x08 
                  movwf   COUNTER 
                  clrf    PARITY 
                  Delay   d'28'		; - 28us - 
ByteInLoop        call    BitIn           ;Data bits 
                  btfss   CLOCK           ;Test for inhibit 
                  retlw   0xFE 		;Inhibit return
                  bcf     STATUS, C 
                  rrf     RECEIVE, f  
                  iorwf   RECEIVE, f 
                  xorwf   PARITY,f 
                  decfsz  COUNTER, f 
                  goto    ByteInLoop 
                  Delay   1		; - 1us -
                  call    BitIn           ;Parity bit 
                  btfss   CLOCK           ;Test for inhibit 
                  retlw   0xFE 
                  xorwf   PARITY, f 
                  Delay   5		; - 5us - 
ByteInLoop1       Delay   1 		; - 1us -
                  call    BitIn           ;Stop bit 
                  btfss   CLOCK           ;Test for inhibit 
                  retlw   0xFE 
                  xorlw   0x00 
                  btfsc   STATUS, Z 
                  clrf    PARITY 
                  btfsc   STATUS, Z        ;Stop bit = 1? 
                  goto    ByteInLoop1      ;  No--keep clocking. 

                  DATA_0  		; DATA => 0    *** Line control bit (ack) 
                  Delay   d'11'		; - 11us -
                  CLOCK_0 		; CLOCK => 0 
                  Delay   d'45'		; - 45us -
                  CLOCK_1 		; CLOCK => 1 
                  Delay   7 		; - 7us -
                  DATA_1  		; DATA => 1 

                  btfss   PARITY, 7        ;Parity correct? 

                  retlw   0xFF             ;  No--return error 

                  Delay   d'45'		; - 45us - 

		  movlw	   0xd1		;debug indicate K: (kbd)
		  call	   SerTx	;debug
		  movf	   RECEIVE,w	;debug
		  call	   SerTx	;debug
                  retlw   0x00 

BitIn             Delay   8 		; - 8us -
                  CLOCK_0  		; CLOCK => 0
                  Delay   d'45'		; - 45us -
                  CLOCK_1  		; CLOCK => 1
                  Delay   d'21'		; - 21us -
                  btfsc   DATA 		; DATA = 1 or 0?
                  retlw   0x80 
                  retlw   0x00

;==================== PS/2 MOUSE COMMUNICATIONS:
;---------------------------------------------------------------------------------------------
; PS/2 Mouse Byte Transmission
;
; RETURN CAUSED BY:
; W = 0xFF Host requesting to send
; W = 0xFE Host Inhibits transmission
; W = 0x00 Transmission of byte went OK

MByteOut		
		  ;call	  SerTx	;debug
                  movwf   TEMP0
MInhibitLoop      btfss   MCLOCK	; Test for inhibit  
                  goto    MInhibitLoop 
                  Delay   d'50'		; - 50us - 
                  btfss   MCLOCK 
                  goto    MInhibitLoop 
                  btfss   MDATA		; Check for request-to-send  
                  retlw   0xFF 		; Return - Host requesting to send

		movf		TEMP0, w ;debug
		call	  	SerTx	;debug

                  clrf    PARITY 
                  movlw   0x08 
                  movwf   COUNTER 
                  movlw   0x00   
                  call    MBitOut	; Start bit (0) 
                  btfss   MCLOCK	; Test for inhibit  
                  goto    MByteOutEnd 
                  Delay   4 		; - 4us -
MByteOutLoop      movf    TEMP0, w 
                  xorwf   PARITY, f 
                  call    MBitOut 	; Data bits 
                  btfss   MCLOCK	; Test for inhibit 
                  goto    MByteOutEnd 
                  rrf     TEMP0, f 
                  decfsz  COUNTER, f 
                  goto    MByteOutLoop 
                  Delay   2 		; - 2us -
                  comf    PARITY, w  
                  call    MBitOut	; Parity bit 
                  btfss   MCLOCK	; Test for inhibit 
                  goto    MByteOutEnd 
                  Delay   5 		; - 5us -
                  movlw   0xFF    
                  call    MBitOut       ; Stop bit (1) 
                  Delay   d'48'		; - 48us -


                  retlw   0x00 		; OK return

MByteOutEnd       MDATA_1
		  MCLOCK_1
                  retlw   0xFE 		;Inhibit Return
     
MBitOut 
                  andlw   0x01 
                  btfss   STATUS, Z 	; Data = 1 or 0?
                  MDATA_1 		;
                  btfsc   STATUS, Z 
                  MDATA_0 		; DATA => 0 or 1
                  Delay   d'21' 	; - 21us -
                  MCLOCK_0 		; CLOCK => 0
                  Delay   d'45' 	; - 45us -
                  MCLOCK_1 		; CLOCK => 1
                  Delay   d'5' 		; - 5us -
                  return


;***************************************************
;PS/2 Mouse Byte Reception
;
;Every byte received from the PC (=Host) must be acknowledged by 0xFA,
; except for 'Resend'(0xFE) and 'Echo'(0xEE) commands.
;
;Reads a byte from the host.  
;Received byte is in "MRECEIVE" register.  
;Returns 0xFD in W if Timeout.  
;Returns 0xFE in W if host aborts transmission.  
;Returns 0xFF in W if framing/parity error detected. 
;Returns 0x00 in W if byte received successfully. 


MByteIn0
		Delay		d'100'		;Timeout basic delay
		decfsz		TEMP0,f		;Timeout loops done?
		goto		MByteIn1	;No.
		retlw		0xFD		;Yes. Return and indicate timeout.
MByteIn           
		     movlw	d'255'		;Set Timeout counter n=255 (n x 100 us)
			movwf	TEMP0
MByteIn1		btfss   MCLOCK	; Wait for start bit 
                  goto    MByteIn0 
                  btfsc   MDATA 
                  goto    MByteIn0 
MByteInTEST
                  movlw   0x08 
                  movwf   COUNTER 
                  clrf    PARITY 
                  Delay   d'28'		; - 28us -
MByteInLoop       call    MBitIn	; Data bits 
                  btfss   MCLOCK	; Test for inhibit 
                  retlw   0xFE 
                  bcf     STATUS, C 
                  rrf     MRECEIVE, f  
                  iorwf   MRECEIVE, f 
                  xorwf   PARITY,f 
                  decfsz  COUNTER, f 
                  goto    MByteInLoop 
                  Delay   1  		; - 1us -
                  call    MBitIn	; Parity bit 
                  btfss   MCLOCK	; Test for inhibit 
                  retlw   0xFE 
                  xorwf   PARITY, f 
                  Delay   5 		; - 5us -
MByteInLoop1      Delay   1 		; - 1us -
                  call    MBitIn        ; Stop bit 
                  btfss   MCLOCK        ; Test for inhibit 
                  retlw   0xFE 
                  xorlw   0x00 
                  btfsc   STATUS, Z 
                  clrf    PARITY 
                  btfsc   STATUS, Z     ; Stop bit = 1? 
                  goto    MByteInLoop1  ;  No--keep clocking. 

                  MDATA_0  		; DATA => 0   *** Line control bit (ack)
                  Delay   d'11'		; - 11us - 
                  MCLOCK_0 		; CLOCK => 0 
                  Delay   d'45'		; - 45us -
                  MCLOCK_1 		; CLOCK => 1 
                  Delay   7 		; - 7us -
                  MDATA_1  		; DATA => 1

                  btfss   PARITY, 7	;Parity correct? 
                  retlw   0xFF		;  No--return error 

		  movlw	  0xd0		;debug indicate M: (mouse)
		  call	  SerTx		;debug
		  movf	  MRECEIVE,W	;debug
		  call	  SerTx		;debug

                  Delay   d'45'		; - 45us - 
                  retlw   0x00 

MBitIn            Delay   8		; - 8us - 
                  MCLOCK_0  		; CLOCK => 0
                  Delay   d'45'		; - 45us -
                  MCLOCK_1  		; CLOCK => 1
                  Delay   d'21'		; - 21us -
                  btfsc   MDATA		; DATA=1 or 0? 
                  retlw   0x80 
                  retlw   0x00

;======================= 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

;*******************************************************************

;  INIT_UART - Initialises UART
;  Enables COM Port receiver and transmitter
;  Make sure to be at Bank 0

INIT_UART
	;Page 357 of 33023a.pdf (PIC Manual):

	BSF	STATUS, RP0	; Go to Bank1
				; ===========
	MOVLW	d'25'		; Set Baud Rate to 9600 (BRGH=1) or 2400 (BRGH=0)
	MOVWF	SPBRG
	;        7     6    5     4    3    2     1     0
	;TXSTA: CSRC  TX9  TXEN  SYNC  -   BRGH  TRMT  TX9D
	;  TXEN= Transmit Enable bit
	;  BRGH= High Baud Rate Select bit (1= High speed)
	;RCSTA: SPEN  RX9  SREN  CREN  -   FERR  OERR  RX9D
	;  SPEN= serial Port Enable bit
	;  CREN= Continuous Receive Enable bit
	MOVLW	0x24 		; 8-bit transmit, transmitter enabled, BRGH=1
	MOVWF	TXSTA		; Asynchronous mode, high speed mode
	;BSF	PIE1, TXIE	; Enable transmit interrupts
	;BSF	PIE1, RCIE	; Enable receive interrupts
	BCF	STATUS, RP0	; Go to Bank 0
				; ============
	MOVLW	0x80		; (8-bit receive, receive enabled > 0x90)
	MOVWF	RCSTA		; Just Serial Port enabled > 0x80
;-----
			;*** USART Transmission - write to reg. 19h TXREG (Bank 0)


        ; enable recevier
        ;MOVLW   (1<<SPEN)|(1<<CREN) ; preset serial port enable and continous receive
        ;MOVWF   RCSTA   ; set it

        ; enable receiver interrupt
        ;MOVLW   PIE1    ; get adress for periphial irq's
        ;MOVWF   FSR     ; setup fsr
        ;BSF     INDF,RCIE ; enable receiver irq
        ;BSF     INTCON,PEIE ; and periphial irq must also be enabled

			;*** USART Receive Register is 1Ah RCREG (Bank 0)
   	return
;---------------

; Serial Transmission of data via USART
	; This is for PS/2 monitoring
;-----------------------------------------------
; M = Mouse PS/2 data in,  K = Kbd PS/2 data in
; 3 = Sending Scroll Wheel data, finalchord is also sent
SerTx
	;RETURN	; DISABLE THIS DEBUG FUNCTION
	btfss	PIR1, TXIF	; check if ready
	goto	$-1
	movwf	TXREG		; transmit byte
	return
;------------------------------------------------
; BAT = 1, MBAT = 2
SerTx1
	btfss	PIR1, TXIF	; check if ready
	goto	$-1
	movwf	TXREG		; transmit byte
	return
;-----------------------------------------------
; Show PS/2 signalling success
; 0xc0 ... 0xC9
; 0xcd timeout, 0xce host abort, 0xcf error, 0xc0 ok
	; error code in w (0xFN, 0x0N => 0xcN)
	
SerTx3
	movwf	Temp		; Store W
	IORLW	0xf0		; xxxx xxxx => 1111 xxxx
	ANDLW	0xcf		; 1111 xxxx => 1100 xxxx	

	btfss	PIR1, TXIF	; check if ready
	goto	$-1
	movwf	TXREG		; transmit byte
	movf	Temp,w		; Recall W
	return

; ByteOut:
; Returns 0xFD in w if timeout.  => 0xcd
; Returns 0xFE in w if host aborts transmission.  => 0xce
; Returns 0xFF in w if framing/parity error detected. => 0xcf
; Returns 0x00 in w if byte received successfully. => 0xc0

;------------------------------------------------
; PS/2 data out
SerTx4
	btfss	PIR1, TXIF	; check if ready
	goto	$-1
	movwf	TXREG		; transmit byte
	return


;----------------

;ASCII CODES:
;000  (nul)  016  (dle)  032 sp  048 0  064 @  080 P  096 `  112 p
;001  (soh)  017  (dc1)  033 !   049 1  065 A  081 Q  097 a  113 q
;002  (stx)  018  (dc2)  034 "   050 2  066 B  082 R  098 b  114 r
;003  (etx)  019  (dc3)  035 #   051 3  067 C  083 S  099 c  115 s
;004  (eot)  020  (dc4)  036 $   052 4  068 D  084 T  100 d  116 t
;005  (enq)  021  (nak)  037 %   053 5  069 E  085 U  101 e  117 u
;006  (ack)  022  (syn)  038 &   054 6  070 F  086 V  102 f  118 v
;007  (bel)  023  (etb)  039 '   055 7  071 G  087 W  103 g  119 w
;008  (bs)   024  (can)  040 (   056 8  072 H  088 X  104 h  120 x
;009  (tab)  025  (em)   041 )   057 9  073 I  089 Y  105 i  121 y
;010  (lf)   026  (eof)  042 *   058 :  074 J  090 Z  106 j  122 z
;011  (vt)   027  (esc)  043 +   059 ;  075 K  091 [  107 k  123 {
;012  (np)   028  (fs)   044 ,   060 <  076 L  092    108 l  124 |
;013  (cr)   029  (gs)   045 -   061 =  077 M  093 ]  109 m  125 }
;014  (so)   030  (rs)   046 .   062 >  078 N  094 ^  110 n  126 ~
;015  (si)   031  (us)   047 /   063 ?  079 O  095 _  111 o  127 (del)


ShowIRpackets
	movf	IRByte1,w	;
	call	SerTx		;
	movf	IRByte2,w	;
	call	SerTx		;
	movf	IRByte3,w	;
	call	SerTx		;
	movf	IRByte4,w	;
	call	SerTx		;
	movlw	d'219'		; end sign
	call	SerTx		;
	return

;********************************************************************************
;=== KEYBOARD AS MOUSE operation ====

; Bit KBDasMOUSE must be set to end up here.
; Chord in finalchord

KeyboardMouse
	movlw	d'63'		; End of mouse operation pressed?
	xorwf	finalchord,w	;
	bnz	KeybMouse2	; No.
	bcf	KBDasMOUSE	; Yes. End this mouse simulation.

	movlw	d'50'	;This dealay is required! Still!!!
	call	DelayWx10ms	;Do not be too hasty....

	;goto	MainLoop

XMainLoop			; Exit to MainLoop and clear chord buffer
	clrf	PrevChord1	; not to send more chords right away
	clrf	PrevChord2
	clrf	Downs
	return	; goto	MainLoop

KeybMouse2
	btfss	M_ENABLE	; Are the mouse PS/2 lines ready for mouse data?
	goto	MBAT		; No. Try doing the Mouse BAT then (0,5 sec).
	;goto	MainLoop	; No. Do not send movement data.
				; Yes. Movement data can be sent via mouse lines.


; for now, this is only a test to see cursor movement
; after having pressed SHIFT ABC-123
;----test
;MoveRight
;	movlw	0x08	;0000 1000 (No buttons pressed)
;	call	MByteOut
;	movlw	0x05 	; (X=5)
;	call	MByteOut
;	movlw	0x00	; (Y=0)
;	call	MByteOut
;----end of test


	movlw	d'63'		; End of mouse operation?
	xorwf	finalchord,w	;
	bnz	MouseAction	; No.
	bcf	KBDasMOUSE	; Yes. End the mouse simulation.
				; No. Go on...
	;goto	MainLoop

;===============================================
;MOUSE OPERATION
;Chord values for the Mouse
;up 		= a+d = 1+8  	= 9
;right up	= d   		= 8
;right		= e   		= 16
;right down	= f   		= 32
;down		= c+f = 4+32 	= 36
;left down	= c   		= 4
;left		= b   		= 2
;left up	= a   		= 1
;Press and Release Left button	= a+b+c = 1+2+4 	= 7 (left click)
;Press and Release Middle button= b+e (shift) = 2+16 	= 18
;Press and Release Right button	= d+e+f = 8+16+32 = 56 (right click)
;Press and Hold Left Button	= a+c = 1+4 	= 5 (now used for left click)
;Press and Hold Right Button	= d+f = 8+32 	= 40(now used for right click)
;Esc	= 31
;Enter	= 59 (double click)
;123-abc= 63

;======= MOVING MOUSE POINTER WITH KEYBOARD =====

;MouseOperation
	;call	MouseAction
	;goto	MainLoop
;	nop
;MouseAction
;	movf	finalchord,W	;abc-123 (to exit Mouse Operation)
;	xorlw	d'63'		;Test if chord=123-abc
;	btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
;	goto	MouseExit	;

	;movf	finalchord,W	;Esc (to exit Mouse Operation)
	;xorlw	d'31'		;Test if chord=123-abc
	;btfsc	STATUS,Z	;Skip if Z=0. Skip if not equal.
	;goto	MouseExit	;
	
;	btfss	AutoRepeat	;Typematic repeat (Autorepeat on)?
;	goto	MouseAction_aa
;	movlw	0x01		;Faster Autorepeat steps
;	movwf	YstepUp
;	movwf	XstepRight
;	movlw	0xff
;	movwf	YstepDown
;	movwf	XstepLeft
;	goto	MouseAction_a
;MouseAction_aa
;	movlw	0x01		;Default steps
;	movwf	YstepUp
;	movwf	XstepRight
;	movlw	0xff
;	movwf	YstepDown
;	movwf	XstepLeft
;MouseAction_a

MouseAction
	movf	finalchord,W;	;Up?
	xorlw	d'9'		;	
	btfsc	STATUS,Z	;
	goto	MoveUp		;Yes.

	movf	finalchord,W;	;FUp?
	xorlw	d'27'		;A+B+D+E=1+2+8+16=27
	btfsc	STATUS,Z	;
	goto	FMoveUp		;Yes.

	movf	finalchord,W;	;UpRight?
	xorlw	d'8'		;'D'	
	btfsc	STATUS,Z	;
	goto	MoveUpRight	;Yes.

	movf	finalchord,W;	;FUpRight?
	xorlw	d'25'		;'A'+'D'+'E' 1+8+16
	btfsc	STATUS,Z	;
	goto	FMoveUpRight	;Yes.

	movf	finalchord,W;	;UpRRight?
	xorlw	d'24'		;'D+E' 8+16	
	btfsc	STATUS,Z	;
	goto	MoveUpRRight	;Yes.

	movf	finalchord,W;	;Right?
	xorlw	d'16'		;	
	btfsc	STATUS,Z	;
	goto	MoveRight	;Yes.

	movf	finalchord,W;	;FRight?
	xorlw	d'56'		;D+E+F=56
	btfsc	STATUS,Z	;
	goto	FMoveRight	;Yes.

	movf	finalchord,W;	;DownRRight?
	xorlw	d'48'		;'F'+'E' 16+32	
	btfsc	STATUS,Z	;
	goto	MoveDRRight	;Yes.

	movf	finalchord,W;	;DownRight?
	xorlw	d'32'		;'F'	
	btfsc	STATUS,Z	;
	goto	MoveDRight	;Yes.

	movf	finalchord,W;	;FDownRight?
	xorlw	d'52'		;E+F+C=16+32+4=52
	btfsc	STATUS,Z	;
	goto	FMoveDRight	;Yes.

	movf	finalchord,W;	;Down?
	xorlw	d'36'		;	
	btfsc	STATUS,Z	;
	goto	MoveDown	;Yes.

	movf	finalchord,W;	;FDown?
	xorlw	d'54'		;B+C+E+F=2+4+16+32=54
	btfsc	STATUS,Z	;
	goto	FMoveDown	;Yes.

	movf	finalchord,W;	;DownLeft?
	xorlw	d'4'		;'C'	
	btfsc	STATUS,Z	;
	goto	MoveDownLeft	;Yes.

	movf	finalchord,W;	;FDownLeft?
	xorlw	d'38'		;B+C+F=2+4+32=38
	btfsc	STATUS,Z	;
	goto	FMoveDownLeft	;Yes.

	movf	finalchord,W;	;DownLLeft?
	xorlw	d'6'		;'B'+'C' 2+4
	btfsc	STATUS,Z	;
	goto	MoveDownLLeft	;Yes.

	movf	finalchord,W;	;Left?
	xorlw	d'2'		;	
	btfsc	STATUS,Z	;
	goto	MoveLeft	;Yes.

	movf	finalchord,W;	;FLeft?
	xorlw	d'7'		;A+B+C=1+2+4=7
	btfsc	STATUS,Z	;
	goto	FMoveLeft	;Yes.

	movf	finalchord,W;	;UpLLeft?
	xorlw	d'3'		;'A'+'B' 1+2
	btfsc	STATUS,Z	;
	goto	MoveUpLLeft	;Yes

	movf	finalchord,W;	;UpLeft?
	xorlw	d'1'		;'A'	
	btfsc	STATUS,Z	;
	goto	MoveUpLeft	;Yes.

	movf	finalchord,W;	;FUpLeft?
	xorlw	d'11'		;A+B+D=1+2+8=11
	btfsc	STATUS,Z	;
	goto	FMoveUpLeft	;Yes.

				;Typematic on?
	btfsc	AutoRepeat	;For chords below this point NO AUTOREPEAT please!
	return	; goto	MainLoop

;--- alternatives 1 for left and right mouse buttons: ENTER and ESC ----
;yyyyy
	movf	finalchord,W;	;Left Button pressed&released?
	xorlw	d'59'		;ENTER = A+B+D+E+F=1+2+8+16+32=59
	btfsc	STATUS,Z	;A+C=5
	goto	PressLeftButton	;Yes.

	movf	finalchord,W;	;Right Button pressed&released?
	xorlw	d'31'		;D+E+F=56; ESC = 31
	btfsc	STATUS,Z	;D+F=8+32=40
	goto	PressRightButton	;Yes.

;--- alternatives 2 for left and right mouse buttons: A+C (U-uml) and D+F (W)----

	movf	finalchord,W;	;Left Button pressed&released?
	xorlw	d'5'		;
	btfsc	STATUS,Z	;A+C=5
	goto	PressLeftButton	;Yes.

	movf	finalchord,W;	;Right Button pressed&released?
	xorlw	d'40'		;
	btfsc	STATUS,Z	;D+F=8+32=40
	goto	PressRightButton	;Yes.

;--- alternative 3 for left mouse button: SHIFT ----

	movf	finalchord,W;	;Left Button pressed&released?
	xorlw	d'18'		;SHIFT = B+E=2+16=18
	btfsc	STATUS,Z	;A+C=5
	goto	PressLeftButton	;Yes.

;	movf	finalchord,W;	;Right Button pressed&released?
;	xorlw	d'40'		;D+E+F=56; ESC = 31
;	btfsc	STATUS,Z	;D+F=8+32=40
;	goto	PressRightButton	;Yes.

;--- Just press left button down for dragging etc.

	movf	finalchord,W;	;Left Button pressed down?
	xorlw	d'45'		;A+C+D+F = 1+4+8+32 = 45
	btfsc	STATUS,Z	; '?'
	goto	LeftButtonDown	;Yes.

;--- Release left (or any) any button

	movf	finalchord,W;	;Left (or any) Button released?
	xorlw	d'12'		;C+D = 12 
	btfsc	STATUS,Z	; '!'
	goto	ReleaseAnyButton	;Yes.


; ADD POSSIBLE OTHER MOUSE FUNCTIONS HERE...

	return	; goto	XMainLoop

;MouseExit

;	movlw	d'50'	;This dealay is required! Still!!!
;	call	DelayWx10ms	;Do not be too hasty....
;Else there will be possily keystrokes sent before Keyboard operation is enabled

;	bcf	KBDasMOUSE	  ;***Exit Mouse mode***
;	call	SendBATsuccessful ;Reset into Keyboard mode!!!
;	goto	MainLoop

MoveUp
	;movlw	0x08 (no buttons pressed)
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x08
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x05 ;YstepUp
	call	MByteOut
	return	; goto	MainLoop
FMoveUp
	;movlw	0x08 (no buttons pressed)
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x08
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x0F ;YstepUp
	call	MByteOut
	return	; goto	MainLoop


MoveUpRight
	;movlw	0x08 (no buttons pressed)
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x08
	call	MByteOut
	movlw	0x03
	call	MByteOut
	movlw	0x03 ;YstepUp
	call	MByteOut
	return	; goto	MainLoop

FMoveUpRight
	;movlw	0x08 (no buttons pressed)
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x08
	call	MByteOut
	movlw	0x0a
	call	MByteOut
	movlw	0x0a ;YstepUp
	call	MByteOut
	return	; goto	MainLoop


MoveUpRRight
	;movlw	0x08 (no buttons pressed)
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x08
	call	MByteOut
	movlw	0x04
	call	MByteOut
	movlw	0x02 ;YstepUp
	call	MByteOut
	return	; goto	MainLoop

; Up/Right: 1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  
;Down/Left: F  E  D  C  B  A  9  8  7  6  5  4  3  2  1

MoveRight
	;movlw	0x08 (no buttons pressed)
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x08
	call	MByteOut
	movlw	0x05 ;XstepRight
	call	MByteOut
	movlw	0x00
	call	MByteOut
	return	; goto	MainLoop
FMoveRight
	;movlw	0x08 (no buttons pressed)
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x08
	call	MByteOut
	movlw	0x0F ;XstepRight
	call	MByteOut
	movlw	0x00
	call	MByteOut
	return	; goto	MainLoop

MoveDRRight
	;movlw	0x28 	;bit7  bit6  bit5  bit4    bit3  bit2  bit1  bit0
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x28
	call	MByteOut;Yovf  Xovf  Ysign Xsign   =1   middle right left Buttons
	movlw	0x04	;            2                          8
	call	MByteOut
	movlw	0xFE ;YstepDown
	call	MByteOut
	return	; goto	MainLoop

MoveDRight ;0010 1000	; 0     0     1     0       1     0     0     0
	;movlw	0x28 	;bit7  bit6  bit5  bit4    bit3  bit2  bit1  bit0
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x28
	call	MByteOut;Yovf  Xovf  Ysign Xsign   =1   middle right left Buttons
	movlw	0x03	;            2                          8
	call	MByteOut
	movlw	0xFD ;YstepDown
	call	MByteOut
	return	; goto	MainLoop

FMoveDRight ;0010 1000	; 0     0     1     0       1     0     0     0
	;movlw	0x28 	;bit7  bit6  bit5  bit4    bit3  bit2  bit1  bit0
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x28
	call	MByteOut;Yovf  Xovf  Ysign Xsign   =1   middle right left Buttons
	movlw	0x0a	;            2                          8
	call	MByteOut
	movlw	0xF6 ;YstepDown
	call	MByteOut
	return	; goto	MainLoop

MoveDown
	;movlw	0x28	;0010 1000
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x28
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0xFB ;YstepDown
	call	MByteOut
	return	; goto	MainLoop
FMoveDown
	;movlw	0x28	;0010 1000
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x28
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0xF0 ;YstepDown
	call	MByteOut
	return	; goto	MainLoop

MoveDownLeft
	;movlw	0x38	;0011 1000 OK
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x38
	call	MByteOut
	movlw	0xFD ;XstepLeft
	call	MByteOut
	movlw	0xFD
	call	MByteOut
	return	; goto	MainLoop
FMoveDownLeft
	;movlw	0x38	;0011 1000 OK
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x38
	call	MByteOut
	movlw	0xF6 ;XstepLeft
	call	MByteOut
	movlw	0xF6
	call	MByteOut
	return	; goto	MainLoop

MoveDownLLeft
	;movlw	0x38	;0011 1000 OK
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x38
	call	MByteOut
	movlw	0xFC ;XstepLeft
	call	MByteOut
	movlw	0xFE
	call	MByteOut
	return	; goto	MainLoop

MoveLeft
	;movlw	0x18	;0001 1000
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x18
	call	MByteOut
	movlw	0xFB ;XstepLeft
	call	MByteOut
	movlw	0x00
	call	MByteOut
	return	; goto	MainLoop
FMoveLeft
	;movlw	0x18	;0001 1000
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x18
	call	MByteOut
	movlw	0xF0 ;XstepLeft
	call	MByteOut
	movlw	0x00
	call	MByteOut
	return	; goto	MainLoop

MoveUpLLeft
	;movlw	0x18	;0001 1000
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x18
	call	MByteOut
	movlw	0xFC ;XstepLeft
	call	MByteOut
	movlw	0x02
	call	MByteOut
	return	; goto	MainLoop

MoveUpLeft
	;movlw	0x18	;0001 1000
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x18
	call	MByteOut
	movlw	0xFC ;XstepLeft
	call	MByteOut
	movlw	0x04
	call	MByteOut
	return	; goto	MainLoop
FMoveUpLeft
	;movlw	0x18	;0001 1000
	movf	KMouseByte1,W	; Buttons pressed etc
	ADDLW	0x18
	call	MByteOut
	movlw	0xF6 ;XstepLeft
	call	MByteOut
	movlw	0x0A
	call	MByteOut
	return	; goto	MainLoop

PressLeftButton
	movlw	d'30'		; reduced from 50 to 30 for making double click possible
	call	DelayWx10ms	; Do not be too hasty to resend
	movlw	0x09		; Due to frequent key scanning
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x01
	movwf	KMouseByte1
;;ReleaseAnyButton
	movlw	0x08
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x00
	call	MByteOut
	clrf	KMouseByte1
	goto	XMainLoop	; Exit and clear chord buffer

LeftButtonDown
	movlw	d'30'		; reduced from 50 to 30
	call	DelayWx10ms	; Do not be too hasty to resend
	movlw	0x09		; Due to frequent key scanning
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x01
	movwf	KMouseByte1
	goto	XMainLoop	; Exit and clear chord buffer

PressMiddleButton
	movlw	d'50'
	call	DelayWx10ms	;Do not be too hasty to resend
	movlw	0x0c
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x04
	movwf	KMouseByte1
	goto	XMainLoop	; Exit and clear chord buffer

PressRightButton
	movlw	d'50'
	call	DelayWx10ms	;Do not be too hasty to resend

	movlw	0x0a
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x01
	movwf	KMouseByte1
;;ReleaseAnyButton
	movlw	0x08
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x00
	call	MByteOut
	clrf	KMouseByte1
	goto	XMainLoop	; Exit and clear chord buffer

ReleaseAnyButton
	movlw	d'50'
	call	DelayWx10ms	;Do not be too hasty to resend
	movlw	0x08
	call	MByteOut
	movlw	0x00
	call	MByteOut
	movlw	0x00
	call	MByteOut
	clrf	KMouseByte1
	goto	XMainLoop		; Exit and clear chord buffer

;********************************************************************************
;===END OF SUBROUTINES===
;mmmmmmm

;=====================================================================================;
;_____________________ Page1 0800h-0FFFh More Program code____________________________;

		org	0x800	; Start of program memory page 1

;-------------------------------------------------------------------------------------

	; This is for check-back timer monitoring
; Send 0xFF then the values of the 3 key press timers
SerTx2
	RETURN	; DISABLE THIS DEBUG FUNCTION
	btfss	PIR1, TXIF	; check if ready
	goto	$-1
	movwf	TXREG		; transmit byte
	return

TestUSART
	;Send text 'GKOS' and a carriage return
	movlw	d'71' ;0x47	;'G'
	call	SerTx2
	movlw	d'75' ;0x4B	;'K'
	call	SerTx2
	movlw	d'79' ;0x4F	;'O'
	call	SerTx2
	movlw	d'83' ;0x53	;'S'
	call	SerTx2
	movlw	d'13' ;0x0D	;<CR>
	call	SerTx2
	return

ClearAutorepeat
		; Mouse simulation?
		; Keyboard/mouse delay
	movlw	TDelay		; Initialize Toggle counter because chord = 0.
	btfsc	KBDasMOUSE	; Is Keyboard operating as mouse (mouse simulation)?
	movlw	MTDelay		; Yes. Use a different delay value.
	movwf	ToggleCounter	; No. Use the kbd delay value as planned.
	bcf	AutoRepeat	; clear autorepeat indication

	movlw	HIGH ClearModes	; Get high 5 bits of address
	movwf	PCLATH		; Previous Page...
	call	ClearModes	; clear SYMB, Alt etc.
	movlw	HIGH GetChordParams ;Make sure PCLATH is pointing to this Page (1)
	movwf	PCLATH

	return

;=============================================================================
; BETTER WAY OF POLLING IR and wired kbd CHORDS
; xxxxxxx (<= to find this point by search)

GetChordParams

	bcf	RXchordREADY	; Default: Indicate to GKOSloop that output shall not be made

	;movf	PrevChord2,w	; Get the chord (may be NUL sometimes!) 2 steps back
	movf	Downs,w		; Get the chord = PrevChord1 AND PrevChord2 (may be NUL!)
	movwf	RXfinalchord	; update IR final chord ****THE CHORD TO SEND****

		; Zero cord?

	incf	RXchord,f	; RXchord = 0?
	decfsz	RXchord,f
	goto	GCP1		; No.
	goto	GCP2		; Yes.

		; Repeated chords?
GCP1				; For AUTOREPEAT, check if previous chord is equal (<>0)
	movf	RXchord,w
	movwf	Temp
	movf	PrevChord1,w
	subwf	Temp,w
	btfss	STATUS,2	; Z=1?, Equal?
	goto	UCP0		; No.
				; Yes.
		; Autorepeat?

	decfsz ToggleCounter,f	; Toggle counter reached zero?
	goto	UCP0		; No.
	incf	ToggleCounter,f	; Yes. Leave as it was.
	bsf	RXchordREADY	; Indicate that char will be output in any case
	bsf	AutoRepeat	; set autorepeat indication
	bcf	TextOnly	; Repeat any character
	goto	UCP0_1


GCP2
		; RXchord = 0

; Update Key down Timer for each key (decreasing values)

UCP0
		; Previous chord is not equal (RXchord<>PrevChord1)

	btfsc	AutoRepeat	; Autorepeat on?
	call	ClearAutorepeat	; Yes. Turn it off.
UCP0_1
	btfss   RXchord,0	; Chord bit0 = 1?
	goto	UCP1		; No. Go on with the next chord bit.
	incf	KeyTime0,f	; add 1 in order to set key counter to 1 if 0
	decfsz	KeyTime0,f	; Decrement key time counter (127...0 !), Zero?
	decf	KeyTime0,f	; Not zero. Decrement if not zero in the beginning
				; Zero. The key has been down long. Do not decrement.
UCP1
	btfss   RXchord,1	; Chord bit1 = 1?
	goto	UCP2		; No. Go on with the next chord bit.
	incf	KeyTime1,f	; add 1 in order to set key counter to 1 if 0
	decfsz	KeyTime1,f	; Decrement key time counter (127...0 !), Zero?
	decf	KeyTime1,f	; Not zero. Decrement if not zero in the beginning
				; Zero. The key has been down long. Do not decrement.
UCP2
	btfss   RXchord,2	; Chord bit2 = 1?
	goto	UCP3		; No. Go on with the next chord bit.
	incf	KeyTime2,f	; add 1 in order to set key counter to 1 if 0
	decfsz	KeyTime2,f	; Decrement key time counter (127...0 !), Zero?
	decf	KeyTime2,f	; Not zero. Decrement if not zero in the beginning
				; Zero. The key has been down long. Do not decrement.
UCP3
	btfss   RXchord,3	; Chord bit3 = 1?
	goto	UCP4		; No. Go on with the next chord bit.
	incf	KeyTime3,f	; add 1 in order to set key counter to 1 if 0
	decfsz	KeyTime3,f	; Decrement key time counter (127...0 !), Zero?
	decf	KeyTime3,f	; Not zero. Decrement if not zero in the beginning
				; Zero. The key has been down long. Do not decrement.
UCP4
	btfss   RXchord,4	; Chord bit4 = 1?
	goto	UCP5		; No. Go on with the next chord bit.
	incf	KeyTime4,f	; add 1 in order to set key counter to 1 if 0
	decfsz	KeyTime4,f	; Decrement key time counter (127...0 !), Zero?
	decf	KeyTime4,f	; Not zero. Decrement if not zero in the beginning
				; Zero. The key has been down long. Do not decrement.
UCP5
	btfss   RXchord,5	; Chord bit5 = 1?
	goto	UCP6		; No. Go on.
	incf	KeyTime5,f	; add 1 in order to set key counter to 1 if 0
	decfsz	KeyTime5,f	; Decrement key time counter (127...0 !), Zero?
	decf	KeyTime5,f	; Not zero. Decrement if not zero in the beginning
				; Zero. The key has been down long. Do not decrement.

;----
UCP6

;============ new code in Paris, September 2003 ============

; This key polling procedure allows some overlapping of chords as well as
; holding down keys between chords supposing at least one key is released.

KeyPoll

		; Check-back enabled?

;	CHECK-BACK IS ALWAYS DONE BUT SELECT LATER IF THE RESULT WILL BE OUTPUT
;	btfsc	CheckBackOn	; Check-back enabled?
;	goto	KeyPoll_CB	; Yes.
;				; No. Just enhanced key polling.
;	btfsc	NoOutput	; Is this too soon after previous output?
;	goto	KP0_NCB		; Yes.
;				; No. Output allowed from now on
;	btfsc	NewChar		; NoOutput=0. Is output assumed (new key pressed)?
;	goto	KP_newchar	; No.
;	goto	KP0 ;KP1_a	; Yes. Any change in chord?
;				; Continue as with check-back
;
;KP0_NCB
;	bcf	NoOutput	; Yes. Too soon. Next time then.
;	goto	KP_newchar
;
;----
		; Any key released? (Check-back enabled)
KeyPoll_CB
	;btfss	NoOutput	; Is this too soon after previous output?
	incf	WaitCounter,f	; Is WaitCounter = 0 or...
	decfsz	WaitCounter,f	; ...is this too soon after previous output?
	goto	KP0		; Yes. To soon.
	;bcf	NoOutput	; Output allowed from now on
	goto	KP1		; 
KP0
	;bcf	NoOutput	; Yes. Too soon.
	decf	WaitCounter,f	;
	goto	KP_newchar
KP1
; <<<<<TEST!!!! DO NOT MIND THE NewChar PARAMETER. JUST THE GUARD TIME!!!!!
;	btfsc	NewChar		; NoOutput=0. Is output supposed (new key pressed)?
;	goto	KP1_a		; Yes. Is there any change in chord?
				; ---------------------------------------
;	movf	RXchord,W	; --- No. Except if this is a zero chord
;	XORLW	d'0'		; --- Zero chord?
;	btfss	STATUS,Z	; --- 3 commented lines during development
				; ---------------------------------------
;	goto	KP_newchar	; No.
				; Yes.
KP1_a				; Is there any change in chord?
	movf	RXchord,w	; RXchord = PrevChord1?
	movwf	Temp		; PrevChord1             011100
	movf	PrevChord1,w	; RXchord                001101
	XORWF	Temp,f		; bits that changed      010001 (XOR)
	ANDWF	Temp,f		; bits that were cleared 010000 (AND)
	btfsc	STATUS,2	; Z=0?, non-zero?, Keys released?
	goto	KP_newchar	; No.
	bsf	RXchordREADY	; Yes. Indicate to GKOSloop that output shall be made.
	movlw	WaitPeriods	; Ignore a key release next N periods. ** ONLY VALID IF NO CHECK-BACK **
	movwf	WaitCounter	; WaitCounter is made relative to chord period C now!
	bsf	NoOutput	; Ignore a key release next time (just 1 period).
	bcf	NewChar		; No more output before a new key is pressed.
		; Keyboard/mouse autorepeat delay
	movlw	TDelay		; Initialize Toggle counter due to output of character.
	btfsc	KBDasMOUSE	; Is Keyboard operating as mouse (mouse simulation)?
	movlw	MTDelay		; Yes. Use a different delay value.
	movwf	ToggleCounter	; No. Use the kbd delay value as planned.
	bcf	AutoRepeat	; clear autorepeat indication

KP_newchar
		; Any new key pressed?

	movf	PrevChord2,w	; PrevChord1 = PrevChord2?
	movwf	Temp		; PrevChord2             011100
	movf	PrevChord1,w	; PrevChord1             001101
	XORWF	Temp,f		; bits that changed      010001 (XOR)
	ANDWF	Temp,f		; bits that were set     000001 (AND)
	btfss	STATUS,2	; Z=0?, non-zero?, New keys pressed?
	bsf	NewChar		; Yes. Indicate that next key release will cause char output.
				; No. A key release will not result in outputting a character.
UpdateDowns
		; Update the chord value that might be output next time

	movf	PrevChord1,w	; RXchord AND PrevChord1
	movwf	Downs		; PrevChord1             011100
	movf	RXchord,w	; RXchord                001101
	ANDWF	Downs,f		; bits that were common  001100 (AND)
	
	; The previous Downs will be the chord to send! Not yet this ANDed value above.
	; The previous Downs has already been moved to RXfinalchord for sending

;============ end of new code in Paris 9/2003 =====

; Check back for double values to indicate missed characters (due to no key released)

;=========================== Code for check-back starts here ===========================
; ADD: control functions like PageUp, UpArrow shall not be accepted aunless preceded
;      by all keys up. Also if check back gives PageUp atc. they shall be rejected.

; ccccccc
	btfss	RXchordREADY	; Is it time to output a character?
	goto	KP_X		; No. Just skip the check-back procedure.
				; Yes. Then check back if there was a missed chord
				;   before the actual one to send.


; 1) Find the shortest KeyTime in PrevChord1 (=C).
;	They must be below 127 because they have been decremented at least once.
;	It is in fact the largest value of KeyTime *down* counters 
;	(max 3 counters for letters/numbers/punctuation).

	; defaults:
	clrf	Tmp3		; Clear temp storage of check-back chord value
	bcf	MoreChords	; Indicate that there is no second chord to send
				;   in the buffer.

	clrf	TempB0	; single keys in chord
	clrf	TempB1
	clrf	TempB2
	movlw	d'127'
	movwf	TEMP0	; Three timers in chord. Set initial values
	movwf	TEMP1	;   for down counters (127...0)
	movwf	TEMP2

	; Code below is long but fast!
	; check PrevChord1 because it does not yet include the key release

CheckBit5
	btfss	RXfinalchord,5
	goto	CheckBit4
	movlw	b'100000'	
	movwf	TempB0
	movf	KeyTime5,W
	movwf	TEMP0
	goto	CheckBit4B
CheckBit4		
	btfss	RXfinalchord,4
	goto	CheckBit3
	movlw	b'010000'	
	movwf	TempB0
	movf	KeyTime4,W
	movwf	TEMP0
	goto	CheckBit3B
CheckBit3		
	btfss	RXfinalchord,3
	goto	CheckBit2
	movlw	b'001000'	
	movwf	TempB0
	movf	KeyTime3,W
	movwf	TEMP0
	goto	CheckBit2B
CheckBit2		
	btfss	RXfinalchord,2
	goto	CheckBit1
	movlw	b'000100'	
	movwf	TempB0
	movf	KeyTime2,W
	movwf	TEMP0
	goto	CheckBit1B
CheckBit1		
	btfss	RXfinalchord,1
	goto	CheckBit0
	movlw	b'000010'	
	movwf	TempB0
	movf	KeyTime1,W
	movwf	TEMP0
	goto	CheckBit0B
CheckBit0		
	btfss	RXfinalchord,0
	goto	CheckBitX
	movlw	b'000001'	
	movwf	TempB0
	movf	KeyTime0,W
	movwf	TEMP0
	goto	CheckBitX
;------------------
CheckBit4B		
	btfss	RXfinalchord,4
	goto	CheckBit3B
	movlw	b'010000'	
	movwf	TempB1
	movf	KeyTime4,W
	movwf	TEMP1
	goto	CheckBit3C
CheckBit3B		
	btfss	RXfinalchord,3
	goto	CheckBit2B
	movlw	b'001000'	
	movwf	TempB1
	movf	KeyTime3,W
	movwf	TEMP1
	goto	CheckBit2C
CheckBit2B		
	btfss	RXfinalchord,2
	goto	CheckBit1B
	movlw	b'000100'	
	movwf	TempB1
	movf	KeyTime2,W
	movwf	TEMP1
	goto	CheckBit1C
CheckBit1B		
	btfss	RXfinalchord,1
	goto	CheckBit0B
	movlw	b'000010'	
	movwf	TempB1
	movf	KeyTime1,W
	movwf	TEMP1
	goto	CheckBit0C
CheckBit0B		
	btfss	RXfinalchord,0
	goto	CheckBitX
	movlw	b'000001'	
	movwf	TempB1
	movf	KeyTime0,W
	movwf	TEMP1
	goto	CheckBitX
;-------------------
CheckBit3C		
	btfss	RXfinalchord,3
	goto	CheckBit2C
	movlw	b'001000'	
	movwf	TempB2
	movf	KeyTime3,W
	movwf	TEMP2
	goto	CheckBitX
CheckBit2C		
	btfss	RXfinalchord,2
	goto	CheckBit1C
	movlw	b'000100'	
	movwf	TempB2
	movf	KeyTime2,W
	movwf	TEMP2
	goto	CheckBitX
CheckBit1C		
	btfss	RXfinalchord,1
	goto	CheckBit0C
	movlw	b'000010'	
	movwf	TempB2
	movf	KeyTime1,W
	movwf	TEMP2
	goto	CheckBitX
CheckBit0C		
	btfss	RXfinalchord,0
	goto	CheckBitX
	movlw	b'000001'	
	movwf	TempB2
	movf	KeyTime0,W
	movwf	TEMP2
	;goto	CheckBitX
;----------

; 3) Find those KeyTime values that exceed (P% x C  =  50% x C to start with). 
;    They will define a second character that must be output before the actual RXfinalchord.
;	C = the shortest KeyTime in the original chord

CheckBitX

	; Here is now each of the one-to-three keys and the correponding timer values
	; Keys: 	TempB0, TempB1, TempB2, e.g. 010000,   000100, 000010 (FECDBA)
	; Timer values: TEMP0,  TEMP1,   TEMP2, e.g. 119(min), 115,    103(max)
	; subwf examples:
	; reg=3, w=2 => C=1, Z=0 (+)
	; reg=2, w=2 => C=1, Z=1 (0)
	; reg=1, w=2 => C=0, Z=0 (-)

	; Subtract each TEMPn from 127 to get real length
	; and clear values that are too small

	movlw	d'255'	; movlw	d'13' ;0x0D = <CR> To show start of data in debug window
	call	SerTx2	;Debug

	movf	TEMP0,W
	sublw	d'127'	; 127-119=8 (subtract W *from* literal)
	movwf	TEMP0	; (min in the example)
	call	SerTx2	;Debug

	;sublw	d'4'		; TEMP0 < 4?
	;btfss	STATUS,C	; C=0 indicates borrow
	;clrf	TEMP0		; 3-4 => borrow

	movf	TEMP1,W
	sublw	d'127'	; 127-115=12 (subtract W *from* literal)
	movwf	TEMP1
	call	SerTx2	;Debug

	;sublw	d'4'		; TEMP1 < 4?
	;btfss	STATUS,C	; C=0 indicates borrow
	;clrf	TEMP1		; 3-4 => borrow

	movf	TEMP2,W
	sublw	d'127'	; 127-103=24 (subtract W *from* literal)
	movwf	TEMP2	; (max in the example)
	call	SerTx2	;Debug

	;sublw	d'4'		; TEMP2 < 4?
	;btfss	STATUS,C	; C=0 indicates borrow
	;clrf	TEMP2		; 3-4 => borrow


;------

	; Disacrd small values 1...3
	



CTEMP0_TEMP1
	; Compare TEMP0 and TEMP1

	movf	TEMP0,W		; TEMP0=0?
	XORLW	d'0'
	btfsc	STATUS,Z
	goto	CTEMP1_TEMP2	; Yes.
				; No.

	movf	TEMP1,W		; TEMP1=0?
	XORLW	d'0'
	btfsc	STATUS,Z
	goto	CTEMP0_TEMP2	; Yes.
				; No.
	movf	TEMP1,W
	subwf	TEMP0,W		; compare TEMP1 and TEMP0: TEMP0-TEMP1
	btfsc	STATUS,Z 	;
	goto	CTEMP1_TEMP2	; Z=1 (TEMP0=TEMP1) ???
	btfsc	STATUS,C
	goto	CTEMP1_TEMP2	; C=1 (TEMP0>TEMP1)
	goto	CTEMP0_TEMP2	; C=0 (TEMP0<TEMP1)

CTEMP1_TEMP2
	; Compare TEMP1 and TEMP2

	movf	TEMP2,W		; TEMP2=0?
	XORLW	d'0'
	btfsc	STATUS,Z
	goto	T1smallest	; Yes.
				; No.
	movf	TEMP2,W
	subwf	TEMP1,W		; compare TEMP2 and TEMP1: TEMP1-TEMP2
	btfsc	STATUS,Z 	;
	goto	T2smallest	; Z=1 (TEMP1=TEMP2) ???
	btfsc	STATUS,C
	goto	T2smallest	; C=1 (TEMP1>TEMP2)
	goto	T1smallest	; C=0 (TEMP1<TEMP2)

CTEMP0_TEMP2
	; Compare TEMP0 and TEMP2

	movf	TEMP2,W		; TEMP2=0?
	XORLW	d'0'
	btfsc	STATUS,Z
	goto	T0smallest	; Yes.
				; No.
	movf	TEMP2,W
	subwf	TEMP0,W		; compare TEMP2 and TEMP0: TEMP0-TEMP2
	btfsc	STATUS,Z 	;
	goto	T0smallest	; Z=1 (TEMP0=TEMP2) ???
	btfsc	STATUS,C
	goto	T2smallest	; C=1 (TEMP0>TEMP2)
	goto	T0smallest	; C=0 (TEMP0<TEMP2)


;------

T0smallest
	movf	TEMP0,W		; divide TEMP0 by two and save into Tmp2
	movwf	Tmp2		; xxxx xxxx
	movwf	WaitCounter	; Update Guard time
	rrf	WaitCounter,f	; divide by 2
	bcf	WaitCounter,7	; 0xxx xxxx
	;incf	WaitCounter,f	; TEMPX=0,1,2,3,4,5,6,7,8,9,10,11,...
				; WtCnt=1,1,2,2,3,3,4,4,5,5, 6, 6,...(6 = 0.180 sec)
	;bsf	WaitCounter,0	; Make sure it is at least 1 (0xxx xxx1)
	clrf	WaitCounter	; Use fixed value
	bsf	WaitCounter,1	; Make sure it is at least 3 (0xxx xx1x)
	bsf	WaitCounter,0	; Make sure it is at least 3 (0xxx xx11)
	;rrf	Tmp2,F		; - 0-7:2, 8-15:6, 16-31:>10
	;bcf	Tmp2,7		; 0xxx xxxx ---> x
				; If Tmp2>4 then decrement by one
	movlw	d'4'		; to adjust larger than 4 values
	subwf	Tmp2,W		; Tmp2-4<0?
	btfsc	STATUS,C	; Carry?
	decf	Tmp2,f		; No. Tmp2>=4
				; Yes. Tmp2<4.
	movf	TEMP0,W		; TEMP1-TEMP0>0.5 x TEMP0?
	subwf	TEMP1,W		; TEMP1=TEMP1-TEMP0 (result)
	subwf	Tmp2,W		; Tmp2 - result =?
	btfsc	STATUS,C	; Second chord found?
	goto	T0s2		; C=1 Tmp2 > result (not found)
	bsf	MoreChords	; C=0 Tmp2 < result ***FOUND

	; get the bit from TempB1 into second chord
	movf	TempB1,W
	movwf	Tmp3	
T0s2
	movf	TEMP0,W		; TEMP2-TEMP0>0.5 x TEMP0?
	subwf	TEMP2,W		; TEMP2=TEMP2-TEMP0 (result)
	subwf	Tmp2,W		; Tmp2 - result =?
	btfsc	STATUS,C	; Second chord found?
	goto	PrepareOutput	; C=1 Tmp2 > result (not found)
	bsf	MoreChords	; C=0 Tmp2 < result ***FOUND

	; get the bit from TempB2 into second chord
	movf	TempB2,W
	addwf	Tmp3,F
	goto	PrepareOutput	; Output two chords

T1smallest
	movf	TEMP1,W		; divide TEMP1 by two and save into Tmp2
	movwf	Tmp2		; xxxx xxxx
	movwf	WaitCounter	; Update Guard time
	rrf	WaitCounter,f	; divide by 2
	bcf	WaitCounter,7	; 0xxx xxxx
	;bsf	WaitCounter,0	; Make sure it is at least 1 (0xxx xxx1)
	;incf	WaitCounter,f	; TEMPX=0,1,2,3,4,5,6,7,8,9,10,11,...
				; WtCnt=1,1,2,2,3,3,4,4,5,5, 6, 6,...
	clrf	WaitCounter	; Use fixed value
	bsf	WaitCounter,1	; Make sure it is at least 3 (0xxx xx1x)
	bsf	WaitCounter,0	; Make sure it is at least 3 (0xxx xx11)
	;rrf	Tmp2,F
	;bcf	Tmp2,7		; 0xxx xxxx ---> x
				; If Tmp2>4 then decrement by one
	movlw	d'4'		; to adjust larger than 4 values
	subwf	Tmp2,W		; Tmp2-4<0?
	btfsc	STATUS,C	; Carry?
	decf	Tmp2,f		; No. Tmp2>=4
				; Yes. Tmp2<4.
	movf	TEMP1,W		; TEMP0-TEMP1>0.5 x TEMP1?
	subwf	TEMP0,W		; TEMP0=TEMP0-TEMP1 (result)
	subwf	Tmp2,W		; Tmp2 - result < 0 ?
	btfsc	STATUS,C	; Second chord found?
	goto	T1s2		; C=1 Tmp2 > result (not found)
	bsf	MoreChords	; C=0 Tmp2 < result ***FOUND

	; get the bit from TempB0 into second chord
	movf	TempB0,W
	movwf	Tmp3	
T1s2
	movf	TEMP1,W		; TEMP2-TEMP1>0.5 x TEMP1?
	subwf	TEMP2,W		; TEMP2=TEMP2-TEMP1 (result)
	subwf	Tmp2,W		; Tmp2 - result =?
	btfsc	STATUS,C	; Second chord found?
	goto	PrepareOutput	; C=1 Tmp2 > result (not found)
	bsf	MoreChords	; C=0 Tmp2 < result ***FOUND

	; get the bit from TempB2 into second chord
	movf	TempB2,W
	addwf	Tmp3,F
	goto	PrepareOutput	; Output two chords



T2smallest
	movf	TEMP2,W		; divide TEMP2 by two and save into Tmp2
	movwf	Tmp2		; xxxx xxxx
	movwf	WaitCounter	; Update Guard time
	rrf	WaitCounter,f	; divide by 2
	bcf	WaitCounter,7	; 0xxx xxxx
	;bsf	WaitCounter,0	; Make sure it is at least 1 (0xxx xxx1)
	;incf	WaitCounter,f	; TEMPX=0,1,2,3,4,5,6,7,8,9,10,11,...
				; WtCnt=1,1,2,2,3,3,4,4,5,5, 6, 6,...
	clrf	WaitCounter	; Use fixed value
	bsf	WaitCounter,1	; Make sure it is at least 3 (0xxx xx1x)
	bsf	WaitCounter,0	; Make sure it is at least 3 (0xxx xx11)
	;rrf	Tmp2,F
	;bcf	Tmp2,7		; 0xxx xxxx ---> x
				; If Tmp2>4 then decrement by one
	movlw	d'4'		; to adjust larger than 4 values
	subwf	Tmp2,W		; Tmp2-4<0?
	btfsc	STATUS,C	; Carry?
	decf	Tmp2,f		; No. Tmp2>=4
				; Yes. Tmp2<4.
	movf	TEMP2,W		; TEMP1-TEMP2>0.5 x TEMP2?
	subwf	TEMP1,W		; TEMP1=TEMP1-TEMP2 (result)
	subwf	Tmp2,W		; Tmp2 - result =?
	btfsc	STATUS,C	; Second chord found?
	goto	T2s2		; C=1 Tmp2 > result (not found)
	bsf	MoreChords	; C=0 Tmp2 < result ***FOUND

	; get the bit from TempB1 into second chord
	movf	TempB1,W
	movwf	Tmp3	
T2s2
	movf	TEMP2,W		; TEMP0-TEMP2>0.5 x TEMP2?
	subwf	TEMP0,W		; TEMP0=TEMP0-TEMP2 (result)
	subwf	Tmp2,W		; Tmp2 - result =?
	btfsc	STATUS,C	; Second chord found?
	goto	PrepareOutput	; C=1 Tmp2 > result (not found)
	bsf	MoreChords	; C=0 Tmp2 < result ***FOUND

	; get the bit from TempB0 into second chord
	movf	TempB0,W
	addwf	Tmp3,F
	;goto	PrepareOutput	; Output two chords

; ...


; 4) Prepare to output two charaters!
	; First, change RXfinalchord to the previous character and then
	; put the actual RXfinalchord to a buffer (RXfinalchord2) that
	; must be output first thing when polling (MainLoop) starts again.

PrepareOutput
	btfsc	CheckBackOn	; Is check-back output in use?
	goto	PrO_1		; Yes.
	bcf	MoreChords	; No. Indicate no additional chord to send
	goto	CLT_0		;
PrO_1
	btfss	MoreChords	; Second chord found?
	goto	CLT_0		; No.
	movf	RXfinalchord,W	; Yes. Get the actual chord to send.
	movwf	Temp		; Save temporarily the original chord
	movwf	RXfinalchord2	; Put it on hold into the buffer for a while.
	movf	Tmp3,W		; get the second chord found through check-back
	movwf	RXfinalchord	; This is the chord to be sent first instead.

	goto	ClearKeyTimes
; ...

	; Clear counters for keys in the original chord (includes the second
	;  chord also) Original chord must be in Temp
CLT_0
	; This is when only the original chord is sent
	movf	RXfinalchord,W	; Get the actual chord to send.
	movwf	Temp		; Save temporarily original chord

	; This is both cases
	; Clear counters of keys in the original chord
ClearKeyTimes
	movlw	d'127'		; Counter is running 127 -> 0 if key is held down 
	btfsc   Temp,0		; Chord bit0 = 1?
	movwf	KeyTime0	; Yes. Init counter.
	btfsc   Temp,1		; Chord bit1 = 1?
	movwf	KeyTime1	; Yes. Init counter.
	btfsc   Temp,2		; Chord bit2 = 1?
	movwf	KeyTime2	; Yes. Init counter.
	btfsc   Temp,3		; Chord bit3 = 1?
	movwf	KeyTime3	; Yes. Init counter.
	btfsc   Temp,4		; Chord bit4 = 1?
	movwf	KeyTime4	; Yes. Init counter.
	btfsc   Temp,5		; Chord bit5 = 1?
	movwf	KeyTime5	; Yes. Init counter.

KP_X

; ======================= Code for check-back ends here =============================


	; Update consecutive chord values

	movf	PrevChord1,w	; Two chords back
	movwf	PrevChord2	; Save chord as previous chord for next time

	movf	RXchord,w	; One chord back
	movwf	PrevChord1	; Save chord as previous chord for next time

	; Initialize the key counter values for those keys that were up

	movlw	d'127'		; Counter is running 127 -> 0 if key is held down 
	btfss   RXchord,0	; Chord bit0 = 1?
	movwf	KeyTime0	; No. Init counter.
	btfss   RXchord,1	; Chord bit1 = 1?
	movwf	KeyTime1	; No. Init counter.
	btfss   RXchord,2	; Chord bit2 = 1?
	movwf	KeyTime2	; No. Init counter.
	btfss   RXchord,3	; Chord bit3 = 1?
	movwf	KeyTime3	; No. Init counter.
	btfss   RXchord,4	; Chord bit4 = 1?
	movwf	KeyTime4	; No. Init counter.
	btfss   RXchord,5	; Chord bit5 = 1?
	movwf	KeyTime5	; No. Init counter.


	return


;===========================================================================;
;_____________________ Page2 1000h-17FFh (spare)____________________________;
;
;	     org	0x1800	;Start of Program Memory Page 3

;----------------
; spare room for program code
;----------------



;mmmmmmm
;===================== TABLES are on Page 3 (1800h-1FFFh) ============================
;
; This part contains the tables to convert GKOS chords to PS/2 AT keyb scan codes
;
; These figures convert the chord value 1-63 to the GKOS character
; reference number 1-63 (continues up to 105 in the table)
;
; The GKOS Character set is logically arranged (alphabetical and numerical order) 
;
; These tables are used to convert the chord all the way to scan codes:
; Table_ChordToRef => Table_GKOSrefToScPointer => Table_ScanCodes_abc
;
;
;===========================================================================;
;_____________________ Page3 1800h-1FFFh Tables ____________________________;

	     org	0x1800	;Start of Program Memory Page 3

;the GKOS chord value is converted into GKOS ref.num. (GKOS specification) 
Table_ChordToRef
            movwf	 PCL
	    retlw        d'1' ;Convert Chord value to GKOS Reference number
	    retlw        d'2'
            retlw        d'15'
            retlw        d'3'
            retlw        d'27'
            retlw        d'19'
            retlw        d'46'
            retlw        d'4'
            retlw        d'42'
            retlw        d'36';  10
            retlw        d'16'
            retlw        d'33'
            retlw        d'28'
            retlw        d'20'
            retlw        d'47'
            retlw        d'5'
            retlw        d'35'
            retlw        d'59';SHIFT (chord=)18
            retlw        d'17'
            retlw        d'32'; 20
            retlw        d'29'
            retlw        d'21'
            retlw        d'48'
            retlw        d'7'
            retlw        d'8'
            retlw        d'9'
            retlw        d'44'
            retlw        d'10'
            retlw        d'41'
            retlw        d'37'; 30
            retlw        d'56'
            retlw        d'6'
            retlw        d'34'
            retlw        d'31'
            retlw        d'18'
            retlw        d'43'
            retlw        d'30'
            retlw        d'22'
            retlw        d'49'
            retlw        d'23'; 40
            retlw        d'24'
            retlw        d'25'
            retlw        d'58'
            retlw        d'26'
            retlw        d'60';SYMB  (chord=)45
            retlw        d'40'
            retlw        d'62';CTRL (chord=)47
            retlw        d'11'
            retlw        d'12'
            retlw        d'13';  50
            retlw        d'38'
            retlw        d'14'
            retlw        d'39'
            retlw        d'45'
            retlw        d'63';ALT (chord=)55
            retlw        d'50'
            retlw        d'51'
            retlw        d'52'
            retlw        d'54'
            retlw        d'53';  60
            retlw        d'55'
            retlw        d'57'
            retlw        d'61' ;123-abc  (chord=)63
            retlw        d'0'
            retlw        d'0'
;return with offset in register W indicating the GKOS ref.num of the chord

;--------
;The table below converts the GKOS ref.num into Scan Code Pointer value
;In 123 mode, the GKOS character ref.num = GKOS ref.num + 64
;
; ***** NOTE FOR DEVELOPING NATIONAL VERSION OF THIS SOFTWARE:
; The values on this table depend on the national keyboard code page in use on the PC.
; Modify values on this table to select the correct national kbd scan codes.
; (Letters a-z and numbers remain the same, for example)

Table_GKOSrefToScPointer  	
            movwf	 PCL
;---------------- abc mode ------------------------
            retlw        d'0' ;a /0	SYMB mode table is 128 steps down.
            retlw        d'1' ;b	Add 128 to GKOSref if using SYMB table.
            retlw        d'2' ;c
            retlw        d'3' ;d     Same goes for 123-mode but GKOSref values
            retlw        d'4' ;e	but add only 64 to GKOSref	
            retlw        d'5' ;f
            retlw        d'6' ;g	SHIFT can be only applied to GKOSref
            retlw        d'7' ;h	values 0-30 (a-ö)???
            retlw        d'8' ;i
            retlw        d'9' ;j /10
            retlw        d'10' ;k
            retlw        d'11' ;l
            retlw        d'12' ;m
            retlw        d'13' ;n
            retlw        d'14' ;o
            retlw        d'15' ;p
            retlw        d'16' ;q
            retlw        d'17' ;r
            retlw        d'18' ;s
            retlw        d'19' ;t /20
            retlw        d'20' ;u
            retlw        d'21' ;v
            retlw        d'22' ;w
            retlw        d'23' ;x
            retlw        d'24' ;y
            retlw        d'25' ;z
            retlw        d'20' ;u (umlaut)
            retlw        d'48' ;å
            retlw        d'51' ;ä
            retlw        d'50' ;ö /30
            retlw        d'59'  ; .
            retlw        d'58'  ; ,
            retlw        d'115' ; !
            retlw        d'137' ; ?
            retlw        d'60'  ; - 35
            retlw        d'52'  ; '
            retlw        d'127' ; /
            retlw        d'183' ; \
            retlw        d'49'  ; ¨
            retlw        d'189' ; ~ /40
            retlw        d'143' ; ^			...up to here.
		;ALL MODES
            retlw        d'97' ;Arrow up -- NAVIGATING
            retlw        d'101' ;Arrow down
            retlw        d'89' ;PgUp
            retlw        d'95' ;PgDn
            retlw        d'36' ;Backspace
            retlw        d'99' ;Arrow left
            retlw        d'205' ;Word left
            retlw        d'87' ;Home
            retlw        d'37' ;Space /50 
            retlw        d'103' ;Arrow right
            retlw        d'207' ;Word right
            retlw        d'93' ;End
		;controls
            retlw        d'42' ;Enter
            retlw        d'38' ;Tab
            retlw        d'43' ;Esc 
            retlw        d'91' ;Del1
            retlw        d'85' ;Ins
            retlw        d'45' ;Shift (RIGHT)
            retlw        d'209' ;SYMB /60 (0xe8) GKOS only
            retlw        d'210' ;123-abc  (0xe9) GKOS only
            retlw        d'40' ;Ctrl (LEFT)
            retlw        d'41' ;Alt /64
         ;123 mode, add 64 to GKOS ref.num
;------------------ 123 mode -------------------------
            retlw        d'26' ;1 /65
            retlw        d'27' ;2
            retlw        d'28' ;3
            retlw        d'29' ;4
            retlw        d'30' ;5
            retlw        d'31' ;6 /70
            retlw        d'35' ;0
            retlw        d'32' ;7
            retlw        d'33' ;8
            retlw        d'34' ;9
            retlw        d'119' ; #
            retlw        d'135' ; ½
            retlw        d'125' ; &
            retlw        d'163' ; @
            retlw        d'53'  ; +
            retlw        d'123' ; % /80
            retlw        d'133' ; =
            retlw        d'24'  ; Y (yen) just 'y'
            retlw        d'149' ; *
            retlw        d'169' ; €
            retlw        d'167' ; $
            retlw        d'165' ; £
            retlw        d'129' ; (
            retlw        d'175' ; [
            retlw        d'56'  ; <
            retlw        d'173' ; { /90
            retlw        d'131' ; )
            retlw        d'177' ; ]
            retlw        d'151' ; >
            retlw        d'179' ; }
; 
            retlw        d'59'  ; . ;Down from here the same as in abc mode...
            retlw        d'58'  ; ,
            retlw        d'115' ; !
            retlw        d'137' ; ?
            retlw        d'60'  ; -
            retlw        d'52'  ; '
            retlw        d'127' ; /
            retlw        d'183' ; \
            retlw        d'49'  ; ¨
            retlw        d'189' ; ~ /40
            retlw        d'143' ; ^
		;ALL MODES
            retlw        d'97' ;Arrow up -- NAVIGATING
            retlw        d'101' ;Arrow down
            retlw        d'89' ;PgUp
            retlw        d'95' ;PgDn /45
            retlw        d'36' ;Backspace
            retlw        d'99' ;Arrow left
            retlw        d'205' ;Word left
            retlw        d'87' ;Home
            retlw        d'37' ;Space /50 
            retlw        d'103' ;Arrow right
            retlw        d'207' ;Word right
            retlw        d'93' ;End
		;controls
            retlw        d'42' ;Enter
            retlw        d'38' ;Tab
            retlw        d'43' ;Esc 
            retlw        d'91' ;Del1
            retlw        d'85' ;Ins
            retlw        d'45' ;Shift (RIGHT)
            retlw        d'209' ;SYMB /60 (0xe8) GKOS only
            retlw        d'210' ;123-abc  (0xe9) GKOS only
            retlw        d'40' ;Ctrl (LEFT)
            retlw        d'41' ;Alt /64

;--------------------- SYMB mode ----------------------------
            retlw        d'26' ;1 /65
            retlw        d'27' ;2
            retlw        d'28' ;3
            retlw        d'29' ;4
            retlw        d'30' ;5
            retlw        d'31' ;6 /70
            retlw        d'35' ;0
            retlw        d'32' ;7
            retlw        d'33' ;8
            retlw        d'34' ;9
            retlw        d'119' ; #
            retlw        d'135' ; ½
            retlw        d'125' ; &
            retlw        d'163' ; @
            retlw        d'53'  ; +
            retlw        d'123' ; % /80
            retlw        d'133' ; =
            retlw        d'24'  ; Y (yen) just 'y'
            retlw        d'149' ; *
            retlw        d'169' ; €
            retlw        d'167' ; $
            retlw        d'165' ; £
            retlw        d'129' ; (
            retlw        d'175' ; [
            retlw        d'56'  ; <
            retlw        d'173' ; { /90
            retlw        d'131' ; )
            retlw        d'177' ; ]
            retlw        d'151' ; >
            retlw        d'179' ; }
	 ;symbols only in SYMB mode (GKOSref 95-105):
            retlw        d'155' ; : /95
            retlw        d'153' ; ; 
            retlw        d'115' ;inverted ! (not implemented for FIN/SWE kbd)
            retlw        d'137' ;inverted ? (not implemented for FIN/SWE kbd)
            retlw        d'157' ; _
            retlw        d'117' ; " /100
            retlw        d'54'  ; ´ 
            retlw        d'139' ; `
            retlw        d'197' ; | 
            retlw        d'55'  ; § 
            retlw        d'121' ; ¤ /105
		;ALL MODES
            retlw        d'97' ;Arrow up -- NAVIGATING
            retlw        d'101' ;Arrow down
            retlw        d'89' ;PgUp
            retlw        d'95' ;PgDn
            retlw        d'36' ;Backspace
            retlw        d'99' ;Arrow left
            retlw        d'205' ;Word left
            retlw        d'87' ;Home
            retlw        d'37' ;Space /50 
            retlw        d'103' ;Arrow right
            retlw        d'207' ;Word right
            retlw        d'93' ;End
		;controls
            retlw        d'42' ;Enter
            retlw        d'38' ;Tab
            retlw        d'43' ;Esc 
            retlw        d'91' ;Del1
            retlw        d'85' ;Ins
            retlw        d'45' ;Shift (RIGHT)
            retlw        d'209' ;SYMB /60 (0xe8) GKOS only
            retlw        d'210' ;123-abc  (0xe9) GKOS only
            retlw        d'40' ;Ctrl (LEFT)
            retlw        d'41' ;Alt /64
;------------------- end of SYMB mode -------------------
; ABOVE, THERE IS ROOM FOR AT LEAST 3 CONSECUTIVE TABLES:
;  3 X 64 = 192 (4 X 64 = 256)
; They are the complete abc, 123 ja SYMB tables.
; All include the same control codes ENTER, CTRL, TAB, at 
; the end part of each table
;
;------------
; Next Table
;------------
;This table converts the Scan code Pointer to Scan Code values
Table_ScanCodes_abc       ;GKOS ref no. / char / offset
            movwf	 PCL
	;Basic characters first, 1-byte scan codes
	    retlw	 0x1c ;1/a/0
            retlw        0x32 ;2 b 1
            retlw        0x21 ;3 c 2
            retlw        0x23 ;4 d 3
            retlw        0x24 ;5 e 4
            retlw        0x2b ;6 f 5
            retlw        0x34 ;7 g 6
            retlw        0x33 ;8 h 7
            retlw        0x43 ;9 i 8
            retlw        0x3b ;10 j 9
            retlw        0x42 ;11 k 10
            retlw        0x4b ;12 l 11
            retlw        0x3a ;13 m 12
            retlw        0x31 ;14 n 13
            retlw        0x44 ;15 o 14
            retlw        0x4d ;16 p 15
            retlw        0x15 ;17 q 16
            retlw        0x2d ;18 r 17
            retlw        0x1b ;19 s 17
            retlw        0x2c ;20 t 17
            retlw        0x3c ;21 u 20
            retlw        0x2a ;22 v 21
            retlw        0x1d ;23 w 22
            retlw        0x22 ;24 x 23
            retlw        0x35 ;25 y 24
            retlw        0x1a ;26 z 25
            retlw        0x16 ;65 1 26
            retlw        0x1e ;66 2 27
            retlw        0x26 ;67 3 28
            retlw        0x25 ;68 4 29
            retlw        0x2e ;69 5 30
            retlw        0x36 ;70 6 31
            retlw        0x3d ;72 7 32
            retlw        0x3e ;73 8 33
            retlw        0x46 ;74 9 34
            retlw        0x45 ;71 0 35
            retlw        0x66 ;Backspace 36
            retlw        0x29 ;Space 37
            retlw        0x0d ;Tab 38
            retlw        0x12 ;(Left) Shift 39
            retlw        0x14 ;(Left) Ctrl 40
            retlw        0x11 ;Alt
            retlw        0x5a ;Enter
            retlw        0x76 ;Esc
            retlw        0x7e ;Scroll
            retlw        0x59 ;(Right) Shift 45
            retlw        0x77 ;Num
	  	  retlw	    0x00 ;<spare>
            retlw        0x54 ;US: [ FIN/SWE: Å (1 r from P)
            retlw        0x5b ;US: ] FIN/SWE: ¨ (2 r from P)
            retlw        0x4c ;US: ; FIN/SWE: Ö (1 r from L) 50
            retlw        0x52 ;US: ' FIN/SWE: Ä (2 r from L)
            retlw        0x5d ;US: \ FIN/SWE: ' (3 r from L, may be 1 l from Backspace also)
            retlw        0x4e ;US: - FIN/SWE: + (1 r from zero)
            retlw        0x55 ;US: = FIN/SWE: ´ (2 r from zero)
            retlw        0x0e ;US: ~ FIN/SWE: § (1 l from 1) 55
            retlw        0x61 ;US:nokey  F/S: < (1 l from Z) 
            retlw        0x5d ;US:nokey  F/S: nokey (UK only) (next to enter) 
            retlw        0x41 ;US: , FIN/SWE: ,
            retlw        0x49 ;US: . FIN/SWE: .
            retlw        0x4a ;US: / FIN/SWE: - 60
            retlw        0x05 ;F1
            retlw        0x06 ;F2
            retlw        0x04 ;F3
            retlw        0x0c ;F4
            retlw        0x03 ;F5  65
            retlw        0x0b ;F6
            retlw        0x83 ;F7
            retlw        0x0a ;F8
            retlw        0x01 ;F9
            retlw        0x09 ;F10  70
            retlw        0x78 ;F11
            retlw        0x07 ;F12
            retlw        0x7c ;number pad *
            retlw        0x7b ;number pad -
            retlw        0x79 ;number pad +  75
            retlw        0x00 ;Keyboard buffer full (PC will sound a beep)
            retlw        0xcc ;spare
            retlw        0xcc ;spare
            retlw        0xcc ;spare
            retlw        0xcc ;spare  80
;-------
;On this table, from this on, some keys take 2 or more locations
;
;0xe5-6 this indicates that Shift (0xe5) or Alt Gr (0xe6) is required for that key
;0xe0   the first byte of the key scan code (usually 0xe0)
;0x54   the second byte of the key scan code (0xe7 is for special cases)
	; 2 locations by character
	; - always point to first of the two bytes!	
         retlw	 0xe0 ;Alt Gr 81
	    retlw	 0x11
	    retlw	 0xe0 ;right ctrl	
	    retlw	 0x14 ;	
	    retlw	 0xe0 ;insert	85
	    retlw	 0x70 ;	
	    retlw	 0xe0 ;Home	
	    retlw	 0x6c ;	
	    retlw	 0xe0 ;pgup	
	    retlw	 0x7d ;	      90
	    retlw	 0xe0 ;delete	
	    retlw	 0x71 ;	
	    retlw	 0xe0 ;End	
	    retlw	 0x69 ;
	    retlw	 0xe0 ;pgdn	95
	    retlw	 0x7a ;	
	    retlw	 0xe0 ;up arrow	
	    retlw	 0x75 ;	
	    retlw	 0xe0 ;left arrow	
	    retlw	 0x6b ;	  100
	    retlw	 0xe0 ;down arrow	
	    retlw	 0x72 ;	
	    retlw	 0xe0 ;right arrow
	    retlw	 0x74 ;	
	    retlw	 0xe0 ;number pad /  105	
	    retlw	 0x4a ;	
	    retlw	 0xe0 ;number pad enter	
	    retlw	 0x5a ;	
	    retlw	 0xe0 ;left Flying Window	
	    retlw	 0x1f ;	110
	    retlw	 0xe0 ;right Flying Window	
	    retlw	 0x27 ;	
	    retlw	 0xe0 ;Pop Up Menu (Application menu)
	    retlw	 0x2f ; 114
	; symbols requiring shift
	; - always point to first of the two bytes!	
	    retlw	 0xe5 ;shift 1	F/S:! 115
	    retlw	 0x16 ;	US: !
	    retlw	 0xe5 ;shift 2	F/S:"
	    retlw	 0x1e ;	US: @
	    retlw	 0xe5 ;shift 3	F/S:#
	    retlw	 0x26 ;	US: # 120
	    retlw	 0xe5 ;shift 4	F/S:¤
	    retlw	 0x25 ;	US: $
	    retlw	 0xe5 ;shift 5	F/S:%
	    retlw	 0x2e ;	US: %
	    retlw	 0xe5 ;shift 6  F/S:&  125
	    retlw	 0x36 ;	US: ^
	    retlw	 0xe5 ;shift 7  F/S:/
	    retlw	 0x3d ;	US: &
	    retlw	 0xe5 ;shift 8  F/S:(
	    retlw	 0x3e ;	US: * 130
	    retlw	 0xe5 ;shift 9  F/S:)
	    retlw	 0x46 ;	US: (
	    retlw	 0xe5 ;shift 0  F/S:=
	    retlw	 0x45 ;	US: )
	    retlw	 0xe5 ;shift § (<=FIN/SWE, key 1) F/S:½  135
	    retlw	 0x0e ;	US: `
	    retlw	 0xe5 ;shift + (key 12, )  F/S: ?
	    retlw	 0x4e ;	US: _
	    retlw	 0xe5 ;shift ´ (key 13, =) F/S: `
	    retlw	 0x55 ;	US: + 140
	    retlw	 0xe5 ;shift Å (key 27, [) F/S: Å
	    retlw	 0x54 ;	US: {
	    retlw	 0xe5 ;shift ¨ (key 28, ]) F/S: ^
	    retlw	 0x5b ;	US: }
	    retlw	 0xe5 ;shift Ö (key 40, ;) F/S: Ö 145
	    retlw	 0x4c ;	US: :
	    retlw	 0xe5 ;shift Ä (key 41, ') F/S: Ä
	    retlw	 0x52 ;	US: "
	    retlw	 0xe5 ;shift ' (key 42)  F/S: *
	    retlw	 0x5d ;	US: |  150
	    retlw	 0xe5 ;shift < (key 45)	 F/S: >
	    retlw	 0x61 ;	
	    retlw	 0xe5 ;shift , (key 53)	 F/S: ;
	    retlw	 0x41 ;	US: <
	    retlw	 0xe5 ;shift . (key 54)	 F/S: :  155
	    retlw	 0x49 ;	US: >
	    retlw	 0xe5 ;shift - (key 55)	 F/S: _  
	    retlw	 0x4a ; US: ?
	    retlw	 0x00 ;spare
	    retlw	 0x00 ;  160
	
	;symbols requiring Alt Gr
	; - always point to first of the two bytes!	
	    retlw	 0xe6 ;Alt Gr 1	 F/S: nothing 161
	    retlw	 0x16 ;	
	    retlw	 0xe6 ;Alt Gr 2	 F/S: @
	    retlw	 0x1e ;	
	    retlw	 0xe6 ;Alt Gr 3	F/S: £   165
	    retlw	 0x26 ;
	    retlw	 0xe6 ;Alt Gr 4	F/S: $
	    retlw	 0x25 ;	
	    retlw	 0xe6 ;Alt Gr 5	F/S: € (sometimes?)
	    retlw	 0x2e ;	170
	    retlw	 0xe6 ;Alt Gr 6 F/S: nothing
	    retlw	 0x36 ;	
	    retlw	 0xe6 ;Alt Gr 7 F/S: {
	    retlw	 0x3d ;	
	    retlw	 0xe6 ;Alt Gr 8 F/S: [   175
	    retlw	 0x3e ;
	    retlw	 0xe6 ;Alt Gr 9 F/S: ]
	    retlw	 0x46 ;	
	    retlw	 0xe6 ;Alt Gr 0 F/S: }
	    retlw	 0x45 ;	 180
	    retlw	 0xe6 ;Alt Gr § (<=FIN/SWE, key 1) F/S: nothing
	    retlw	 0x0e ;	
	    retlw	 0xe6 ;Alt Gr + (key 12, ) F/S: \
	    retlw	 0x4e ;	
	    retlw	 0xe6 ;Alt Gr ´ (key 13, =) F/S: nothing    185
	    retlw	 0x55 ;
	    retlw	 0xe6 ;Alt Gr Å (key 27, [) F/S: nothing
	    retlw	 0x54 ;
	    retlw	 0xe6 ;Alt Gr ¨ (key 28, ]) F/S: ~
	    retlw	 0x5b ;	  190
	    retlw	 0xe6 ;Alt Gr Ö (key 40, ;) F/S: nothing
	    retlw	 0x4c ;	  
	    retlw	 0xe6 ;Alt Gr Ä (key 41, ') F/S: nothing
	    retlw	 0x52 ;	
	    retlw	 0xe6 ;Alt Gr ' (key 42, \) F/S: nothing 195
	    retlw	 0x5d ;	
	    retlw	 0xe6 ;Alt Gr < (key 45) F/S: |  
	    retlw	 0x61 ;
	    retlw	 0xe6 ;Alt Gr , (key 53) F/S: nothing
	    retlw	 0x41 ;	 200
	    retlw	 0xe6 ;Alt Gr . (key 54) F/S: nothing
	    retlw	 0x49 ;	  
	    retlw	 0xe6 ;Alt Gr - (key 55) F/S: nothing
	    retlw	 0x4a ; 204
	;special cases (0xe7...0xef)
	retlw		0xea	;Word Left  (ctrl+left arrow, USE RIGHT ctrl) 205
	retlw		0xee	; spare
	retlw		0xeb	;Word Right(ctrl+right arrow, USE RIGHT ctrl) 207
	retlw		0xef	; spare
	retlw		0xec	;SYMB    (no scan code) GKOS only  209
	retlw		0xed	;123-ABC (no scan code) GKOS only  210
	retlw		0xe7	;Pause 211
	retlw		0xe8	;Print Screen 212
	retlw		0xe9	; spare 213
		;MAX 255 !

	; Serial port Message example:

;	movwf	PCL
;	retlw	'o'	;ASCII 'o'
;	retlw	'k'	;ASCII 'k'
;	retlw	'!'	;ASCII '!'
;	retlw	d'0'	;decimal zero


; ==========START OF US KEYBOARD TABLE====================
;
;	     choose this org if both tables are used in the same program
; This the US keyboard version of Table_GKOSrefToScPointer
; It is called istead  	
;
	    org		 0x1A00	; later in program Memory Page 3, after FIN/SWE table
US_Table_GKOSrefToScPointer
            movwf	 PCL
;---------------- abc mode ------------------------
            retlw        d'0' ;a /0	SYMB mode table is 128 steps down.
            retlw        d'1' ;b	Add 128 to GKOSref if using SYMB table.
            retlw        d'2' ;c
            retlw        d'3' ;d    Same goes for 123-mode GKOSref values
            retlw        d'4' ;e	but then add only 64 to GKOSref	
            retlw        d'5' ;f
            retlw        d'6' ;g	SHIFT can be only applied to GKOSref
            retlw        d'7' ;h	values 0-30 (a-ö) - valid for FIN/SWE!
            retlw        d'8' ;i
            retlw        d'9' ;j /10
            retlw        d'10' ;k
            retlw        d'11' ;l
            retlw        d'12' ;m
            retlw        d'13' ;n
            retlw        d'14' ;o
            retlw        d'15' ;p
            retlw        d'16' ;q
            retlw        d'17' ;r
            retlw        d'18' ;s
            retlw        d'19' ;t /20
            retlw        d'20' ;u
            retlw        d'21' ;v
            retlw        d'22' ;w
            retlw        d'23' ;x
            retlw        d'24' ;y
            retlw        d'25' ;z
            retlw        d'145' ;u (umlaut) <= not on US kbd (repeat char) d'145' = :
            retlw        d'55'  ;å          <= not on US kbd               d'55'  = `
            retlw        d'50'  ;ä          <= not on US kbd               d'50'  = ;
            retlw        d'121' ;ö /30      <= not on US kbd               d'121' = $
            retlw        d'59'  ; .
            retlw        d'58'  ; ,
            retlw        d'115' ; !
            retlw        d'157' ; ? 	
            retlw        d'53'  ; - 35
            retlw        d'51'  ; '
            retlw        d'60'  ; /
            retlw        d'52'  ; \
            retlw        d'143'  ; ¨ <= does not exist in US kbd d'143' = }
            retlw        d'135' ; ~ /40
            retlw        d'141' ; ^	<= not US	 d'141' = {
		;ALL MODES
            retlw        d'97' ;Arrow up -- NAVIGATING
            retlw        d'101' ;Arrow down
            retlw        d'89' ;PgUp
            retlw        d'95' ;PgDn
            retlw        d'36' ;Backspace
            retlw        d'99' ;Arrow left
            retlw        d'205' ;Word left
            retlw        d'87' ;Home
            retlw        d'37' ;Space /50 
            retlw        d'103' ;Arrow right
            retlw        d'207' ;Word right
            retlw        d'93' ;End
		;controls
            retlw        d'42' ;Enter
            retlw        d'38' ;Tab
            retlw        d'43' ;Esc 
            retlw        d'91' ;Del1
            retlw        d'85' ;Ins
            retlw        d'45' ;Shift (RIGHT)
            retlw        d'209' ;SYMB /60 (0xe8) GKOS only
            retlw        d'210' ;123-abc  (0xe9) GKOS only
            retlw        d'40' ;Ctrl (LEFT)
            retlw        d'41' ;Alt /64
         ;123 mode, add 64 to GKOS ref.num
;------------------ 123 mode -------------------------
            retlw        d'26' ;1 /65
            retlw        d'27' ;2
            retlw        d'28' ;3
            retlw        d'29' ;4
            retlw        d'30' ;5
            retlw        d'31' ;6 /70
            retlw        d'35' ;0
            retlw        d'32' ;7
            retlw        d'33' ;8
            retlw        d'34' ;9
            retlw        d'119' ; #
            retlw        d'37'  ; ½  <= not on US kbd
            retlw        d'127' ; &
            retlw        d'117' ; @
            retlw        d'139' ; +
            retlw        d'123' ; % /80
            retlw        d'54'  ; =
            retlw        d'24'  ; Y (yen) just 'y'
            retlw        d'129' ; *
            retlw        d'37'  ; € no
            retlw        d'121' ; $
            retlw        d'37'  ; £ no
            retlw        d'131' ; (
            retlw        d'48'  ; [
            retlw        d'153' ; <
            retlw        d'141' ; { /90
            retlw        d'133' ; )
            retlw        d'49'  ; ]
            retlw        d'155' ; >
            retlw        d'143' ; }
 
            retlw        d'59'  ; . ;Down from here the same as in abc mode...
            retlw        d'58'  ; ,
            retlw        d'115' ; !
            retlw        d'157' ; ?
            retlw        d'53'  ; -
            retlw        d'51'  ; '
            retlw        d'60'  ; /
            retlw        d'52'  ; \
            retlw        d'143'  ; ¨ <= no US d'143' = }
            retlw        d'135' ; ~ /40
            retlw        d'141' ; ^  <= no US d'141 = {
		;ALL MODES
            retlw        d'97' ;Arrow up -- NAVIGATING
            retlw        d'101' ;Arrow down
            retlw        d'89' ;PgUp
            retlw        d'95' ;PgDn /45
            retlw        d'36' ;Backspace
            retlw        d'99' ;Arrow left
            retlw        d'205' ;Word left
            retlw        d'87' ;Home
            retlw        d'37' ;Space /50 
            retlw        d'103' ;Arrow right
            retlw        d'207' ;Word right
            retlw        d'93' ;End
		;controls
            retlw        d'42' ;Enter
            retlw        d'38' ;Tab
            retlw        d'43' ;Esc 
            retlw        d'91' ;Del1
            retlw        d'85' ;Ins
            retlw        d'45' ;Shift (RIGHT)
            retlw        d'209' ;SYMB /60 (0xe8) GKOS only
            retlw        d'210' ;123-abc  (0xe9) GKOS only
            retlw        d'40' ;Ctrl (LEFT)
            retlw        d'41' ;Alt /64

;--------------------- SYMB mode ----------------------------
            retlw        d'26' ;1 /65
            retlw        d'27' ;2
            retlw        d'28' ;3
            retlw        d'29' ;4
            retlw        d'30' ;5
            retlw        d'31' ;6 /70
            retlw        d'35' ;0
            retlw        d'32' ;7
            retlw        d'33' ;8
            retlw        d'34' ;9
            retlw        d'119' ; #
            retlw        d'37'  ; ½ no
            retlw        d'127' ; &
            retlw        d'117' ; @
            retlw        d'139' ; +
            retlw        d'123' ; % /80
            retlw        d'54'  ; =
            retlw        d'24'  ; Y (yen) just 'y' <= not on US kbd
            retlw        d'129' ; *
            retlw        d'37'  ; € <= not on US kbd
            retlw        d'121' ; $
            retlw        d'37'  ; £ <= not on US kbd
            retlw        d'131' ; (
            retlw        d'48'  ; [
            retlw        d'153' ; <
            retlw        d'141' ; { /90
            retlw        d'133' ; ) ---
            retlw        d'49'  ; ]
            retlw        d'155' ; >
            retlw        d'143' ; }
	 ;symbols only in SYMB mode (GKOSref 95-105):
            retlw        d'145' ; : /95
            retlw        d'50'  ; ; 
            retlw        d'157' ;inverted ! (not implemented for FIN/SWE kbd)
            retlw        d'115' ;inverted ? (not implemented for FIN/SWE kbd)
            retlw        d'137' ; _
            retlw        d'147' ; " /100
            retlw        d'37'  ; ´ <= not on US kbd 
            retlw        d'55'  ; `
            retlw        d'149' ; | 
            retlw        d'37'  ; §  <= not on US kbd
            retlw        d'37'  ; ¤ /105  <= not on US kbd
		;ALL MODES
            retlw        d'97' ;Arrow up -- NAVIGATING
            retlw        d'101' ;Arrow down
            retlw        d'89' ;PgUp
            retlw        d'95' ;PgDn
            retlw        d'36' ;Backspace
            retlw        d'99' ;Arrow left
            retlw        d'205' ;Word left
            retlw        d'87' ;Home
            retlw        d'37' ;Space /50 
            retlw        d'103' ;Arrow right
            retlw        d'207' ;Word right
            retlw        d'93' ;End
		;controls
            retlw        d'42' ;Enter
            retlw        d'38' ;Tab
            retlw        d'43' ;Esc 
            retlw        d'91' ;Del1
            retlw        d'85' ;Ins
            retlw        d'45' ;Shift (RIGHT)
            retlw        d'209' ;SYMB /60 (0xe8) GKOS only
            retlw        d'210' ;123-abc  (0xe9) GKOS only
            retlw        d'40' ;Ctrl (LEFT)
            retlw        d'41' ;Alt /64

; ==========END OF US KEYBOARD TABLE====================

	END                     ; directive 'end of program'

