; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;                                                                     ;
;   This PIC code, glcdXX.asm, is a further development of gkp22.asm  ;
;   to create an LCD communicator with IR reception and transmission. ;
;   It is capable of receiving and transmitting infrared GKOS code    ;
;   (as defined at gkos.net), driving an LCD display and polling a    ;
;   GKOS keyboard. It sends the specified GKOS infrared signal and    ;
;   can also operate as a remote control for a PC equipped with the   ;
;   GKOS infrared interface (gkpXX.asm).                              ;
;                                                                     ;
;   As most of the latest GKOS PIC software, it implements also:      ;
;   - clever key polling mechanism and to allow entering of chordons  ;
;   i.e. chord chains (chord on chord without release of all keys).   ;
;                                                                     ;
;                                                                     ;
;           This software implements the GKOS IR Communicator         ;
;                                                                     ;
;         "The GKOS SixBack Infrared Hyper Typer Communicator"        ;
;                                                                     ;
; Assembly code generation on the PICmicro PIC16F876 with 4 MHz clock.;
;                         More at gkos.net                            ;
;                                                                     ;
;                                                                     ;
;             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:	    glcd18.asm                                        *
;    Date:          1 April 2004                                      *
;    File Version:  1.8                                               *
;                                                                     *
;    Author:        Seppo Tiainen, Veikkola, Finland                  *
;    Website:       gkos.net (building), gkos.com (specification)     *
;    Email:         gkos@gkos.com                                     *
;                                                                     * 
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;
;   Version history:
;
;   glcd18.asm Wired GKOS keyboard scan improvment
;   glcd17.asm SLEEP function added
;   glcd16.asm finalising capabilities for the wired GKOS keyboard,
;              turn on LCD/IR receiving power
;   glcd15.asm wiring change: LCD bus moved to RA2-5 (was: 0-3)
;   glcd12.asm IR transmission added
;   glcd11.asm more complete display functions (SHIFT, Arrows etc.)
;   glcd10.asm first version to test LCD basics
;   gkp22.asm  Used partly
;
;---------------------------------------------------------------------|
;                                                                     |
;   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)
;-------------------------------------------
; LCD UNIT pin numbers
;         --------------------
;         1  VSS       8   DB1
;         2  VDD       9   DB2
;         3  Vo_       10  DB3
;         4  D/I_      11  DB4
;         5  R/W       12  DB5
;         6  E         13  DB6
;         7  DB0       14  DB7
;         --------------------
;
;=================== 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

TEMPY		EQU	0x3f	; a very local variable, LCD and IR TX
TEMPX		EQU	0x40	; A local variable used in IR TX&RX and LCD output
;TXstatus	EQU	0x41	; spare (bit0=1 => Return from ByteOut without sending.)
				; spare (bit1=1 <= There was Reception during ByteOut)
;TXBYTE		EQU	0x42	; spare (The Original Byte to be sent)
;TXBYTEtemp	EQU	0x43	; spare (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
				; bit1=1 a Zero Chord must be sent when possible.
				; bit2=1 if character comes from IR link; 0 for own keyboard
				; - this is used to show the character on correct LCD line
				; bit3 follows the value of bit2 to notice the change

;---PS2 flags----
PS2flags	EQU	0x46	; bit0=1 (Keyboard enable (K_ENABLE) received from Host)
				; bit1=1 (Mouse enable (M_ENABLE) received from Host)
				; bit2=1 LCD busy
				; bit3=1 US version of keyboard
				; bit4=1 LCD 8-bit mode on
				; bit7=1 MoreChords (in buffer RXfinalchord2) to be sent via PS2
;TempShift2	EQU	0x47	; spare (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 LCD edge passed
				;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
				;bit7=1 LCD_busycheck=1 => Busy flag can be tested

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	; spare (Number of 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
;<<DEVICE literal is used directly in IR TX ;xxxaaadg  x x x A2   A1 A1 D7(1) D6(G)>>
IRdevice	EQU	0x63	; IR Device code in IR RX (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
;
temp01		EQU	0x74	; IR Transmission varable
bitcounter	EQU	0x75	; IR Transmission varable

LCD_DDaddress	EQU	0x76	; Display Data RAM address
LCD_CGaddress	EQU	0x77	; Character Generator RAM address

SLEEPcnt1	EQU	0x78	;counter to goto sleep when no key activity
SLEEPcnt2	EQU	0x79	;counter to goto sleep when no key activity
SLEEPcnt3	EQU	0x7a	;counter to goto sleep when no key activity


;====
;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	SLEEPdelay d'100' ;d'3'	; 1 => 3 sec (nx3s) Idle Time before going to sleep
				; 5 min = 300 sec = 100 x 3s => SLEEPdelay = 100
				; For tests: 9 sec => SLEEPdelay = 3

; LCD Data lines D7 D6 D5 D4 = PORTA, 2-5 (PORTA,0-1 are for mouse Yin Xin)

#define LCD_power	PORTC,1		; LCD and IR receiver power ON.
#define	LCD_RS		PORTC,2		; LCD Register Select
#define	LCD_RW		PORTC,3		; LCD R/W
#define	LCD_E		PORTC,4		; LCD Enable
#define	LCD_busy	PS2flags,2	; LCD busy flag
#define	LCD_busycheck	PS2flags,7	; LCD busy flag can be checked

#define TESTPOINT	PORTC,7  ;4	;=4>7 Test point (pin) for IR reception timing

#define	IRTXDATA	PORTC,0		; IR TX data output port pin
;#define MDEVICE		b'00000111' ;A2-A0 = 111 (not used yet in this version)
;				  ---00aaa(- - - Z A3 A2 A1 A0) Z A3 = 00 (pointer data)
					; IR TX device is defined here:
#define DEVICE		b'00011110'	;A2-A0 = 111,  dg = 1 G
;				  xxxaaadg            gdaaa     gdaaa-
;				b'00011110' => scope: 01111, ...011110 (=MD) gdaaa0
;
#define	IRDATA		PORTB,6		; IR Data input. Low when IR pulse. Internal pull-up used.
#define	AutoRepeat	GKOSstatus,1	; autorepeat indication
#define LCD_edge	IRflags,1	; LCD display edge has been passed, shift needed
#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
#define ZeroChordMissing	tempflags,1	; A zero chord must be sent as soon as possible
#define RecChar		tempflags,2	; RecChar=1 if the character is received via IR link
					;  -show on LCD top line then
#define RecCharPrev	tempflags,3	; Follows the value of RecChar to notice the change
					; 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 GKOSdelay	d'25'		; Delay before re-scanning the wired GKOS

;#define K_ENABLE	PS2flags,0	; spare (Keyboard ENABLE received from Host)
;#define M_ENABLE	PS2flags,1	; spare (Mouse ENABLE received from Host)
#define	US_version	PS2flags,3	; US version of keyboard in use
#define Eight_bit_mode	PS2flags,4	; LCD 8-bit mode ON.
	; ...
#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...


;======================= ...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 Enhanced key polling precedures. LCD encoding. 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'10100000'	; binary value, 1 bit per port bit
	movwf	TRISC		; RC0 IR TX, RC1 LCD_power
				; RC2 LCD_RS (reg.sel.) RC3 LCD_RW
				; RC4 LCD_enable (was: 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 - LCD data bus (+ mouse spare pins)
				; ------
	movlw	b'11111111'	; binary value, 1 bit per port bit
	movwf	TRISA		; RA0,1,6,7 set to inputs (2 spare pins, R0,1)
				; RA2-5 outputs for LCD 4-bit data bus

				;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	tempflags
	clrf	MouseByte1
	clrf	KMouseByte1

	bcf	LCD_E
	clrf	LCD_DDaddress	; Display Data RAM address
	clrf	LCD_CGaddress	; Character Generator RAM address
	bsf	LCD_power	; Turn on LCD and IR receiver power

	movlw	TDelay		; Initialize autorepeat down counter.
	movwf	ToggleCounter	; Use the kbd delay value.

		;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
;=========================================================================


	; Prepare for SLEEP operation
	bcf	INTCON, RBIF	; Clear Port B interrupt flag (just to make sure)
	bsf	INTCON, RBIE	; Enable Port B interrupts

	movlw	d'255'
	movwf	SLEEPcnt1
	movwf	SLEEPcnt2
	movlw	SLEEPdelay	; This defines the ilde time before going to sleep
	movwf	SLEEPcnt3  ; 1=> 5s, 5=> 26s, 50=> 4:10 60=> 5 min, 100=> 8:20


; Basic assurance test results are reported to host


BAT
	;call	BATsub
	;goto	LCD_set

BATsub
	;movlw	d'50'
	;call	DelayWx10ms
	;call	SendBAT		; Keyboard
	;movlw	d'1'
	;call	SerTx1		;debug
	;return

MBAT
	;movlw	d'50'
	;call	DelayWx10ms
	;call	MSendBAT	; Mouse
	;movlw	d'2'
	;call	SerTx1		;debug

;--------------- INITIALIZE LCD ----------------------------------------------

	; Wait 1 seconds for the LCD to start
	movlw	d'100'
	call	DelayWx10ms

	movlw	HIGH LCD_set	; Get high 5 bits of address
	movwf	PCLATH		; Next Page...
	call	LCD_set		; Do the common IR/wired keyboard procedure
	movlw	HIGH main 	; Make sure PCLATH is pointing to this Page (0)
	movwf	PCLATH
;------------------------------------------------------------------------------


;============================ 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

	; Principle: Cut out characters that cannot be within a chordon
	; In case previous chord was zero, any next character 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

;---------------------
;===== PS/2 MOUSE ====
;---------------------
MainL_Mouse

;------------------------------
;==== 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 variable sometimes may be '1' in error!)

	bcf	MoreChords	; Clear flag to avoid repeating this.
	call	PS2SendChord_2	; Send RXfinalchord2 (now in RXfinalchord) to
	goto	MainLoop	;   LCD and IR.

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.

	; Send the GKOS keyboard status after each scan, non-zero chords + zero tails
	; Chord IR packet - takes about 18 ms to send
	call	SendStart	; 2200us pulse
	movf	chord,W		; chord must be in W
	call	SendChord_W	; 6 bits
	call	SendDevice	; 5 bits (00010 = Betamax)


	bcf	RecChar		; Show on LCD lower line
	call	PS2SendChord	; Scan RXchords and send to LCD

; ------------

;----------------------
;==== 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	MainLoopX	;  -Right. Skip the rest.

	; IR data rceived

	btfss	TEMPX,0		; Chord IR data received?
	goto	MainL_IRa	; No.
	bsf	RecChar		; Yes. Show on LCD top line
	call	PS2SendChord	; Scan RX chords and send to LCD.
	goto	MainLoop
MainL_IRa
	btfss	TEMPX,1		; Movement IR data received?
	goto	MainL_IRb	; No.
	goto	MainLoop ;PS2SendMov	; Yes. Send it via PS2 mouse data/clock lines.
					; Remember to send Zero Chord first if needed.
MainL_IRb
	btfsc	TEMPX,2		; Scroll wheel IR data received?
	goto	MainLoop	; No.
	;call	PS2SendScroll	; Yes. Send it via PS2 mouse data/clock lines.

;---------
MainLoopX
	call 	SLEEP_loop	; time to goto sleep? ***************
	goto	MainLoop

;---------------------------------------
SendZeroChord
	;call	SendPause	; Pause 10 ms
	;clrf	finalchord

	;Idle chord IR packet (chord=W=0) - takes about 18 ms to send
	call	SendStart		;2200us pulse
	movlw	d'0'
	call	SendChord_W		;6 bits
	call	SendDevice		;5 bits (00010 = Betamax)
	bcf	ZeroChordMissing	; clear flag

	return
;------------- 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
	call	PS2Output
	movlw	d'26'	; i
	call	PS2Output
	movlw	d'14'	; t
	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
	return
PS2word_the
	movlw	d'14'	; t
	call	PS2Output
	movlw	d'25'	; h
	call	PS2Output
	movlw	d'16'	; e
	call	PS2Output
	return
PS2word_that
	movlw	d'14'	; t
	call	PS2Output
	movlw	d'25'	; h
	call	PS2Output
	movlw	d'1'	; a
	call	PS2Output
	movlw	d'14'	; t
	call	PS2Output
	return
PS2word_have
	movlw	d'25'	; h
	call	PS2Output
	movlw	d'1'	; a
	call	PS2Output
	movlw	d'38'	; v
	call	PS2Output
	movlw	d'16'	; e
	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'4'	; c
	call	PS2Output
	movlw	d'25'	; h
	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
	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.
				; Yes.

PS2SendChord_2


				; 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	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 => LCD code

			;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 < 31. 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	CheckShift	;no, just continue
	movlw	d'126'		;yes, use SYMB table
	movwf	GKOSrefshift	;Mode two sets down to SYMB table
	goto	CheckX
CheckShift			; GKOSref = 1...30?
	movlw	d'31'		; 
	subwf	GKOSref,W	; GKOSref - 31 = positive or zero?
	btfsc	STATUS,C	; Carry staying zero? Note: C = complement of Borrow
	goto	CheckX		; Carry not set. Then GKOSref > 31. No more action.
	btfss	SHIFTon		;
	goto	CheckX
	movlw	d'189'		; yes, use SHIFT table
	movwf	GKOSrefshift	; 
CheckX
	movf	GKOSref,W	;use the selected shift in tables (abc,123,SYMB)
	addwf	GKOSrefshift,F	;GKOSrefshift The final pointer = ref + shift now
	call	GKOSrefToLCDcode	;Get the corresponding LCD character code


; ---------- ADD IR TRANSMISSION OF FINALCHORD HERE ----------------
; Send finalchord + idle chord,
; or use toggle bit and send only finalchord! gkpc22 does not 
; check toggle bit in IR reception! Idle must follow!
;fgfgfgfg

; ADD HERE: Send finalchord + idle chord only if the chord comes from
;           the keyboard of this device; not from IR reception

	; Takes 46 ms (two IR chords sent: finalchord and idle chord)

	;Chord IR packet (finalchord) - takes about 18 ms to send
	;call	SendStart	;2200us pulse
	;call	SendChord	;6 bits
	;call	SendDevice	;5 bits (00010 = Betamax)

	;bsf	ZeroChordMissing	; Set flag so that Chord with
					; zero value will be sent later

	;call	SendPause	; Pause 10 ms
	;clrf	finalchord

	;Idle chord IR packet (chord=W=0) - takes about 18 ms to send
	;call	SendStart	;2200us pulse
	;movlw	d'0'
	;call	SendChord_W	;6 bits
	;call	SendDevice	;5 bits (00010 = Betamax)


;--------------------------------------------------------------

	movf	scpointer,W		; This is added due to changes for LCD version
	movwf	TEMPX			; -"-

; ------------- call LCD procedures ----------------

	movlw	HIGH LCD_proc	; Get high 5 bits of address
	movwf	PCLATH		; Load high address in latch
	call	LCD_proc	; LCD output etc. OUTPUTS TEMPX
	movlw	HIGH MainL_IR	; Make sure PCLATH is pointing to this Page (0)
	movwf	PCLATH

	; Remove shifts but keep CAPS
	call	ClearModes

	return



;--------------------- THE TABLE CALLS ARE HERE ---------------
			;Read data

;Table_ChordToRef => Table_GKOSrefToLCDcode => 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

GKOSrefToLCDcode
	;THEN convert the GKOSref to scpointer
	;This code allows accessing a table anywhere in program memory
	movlw	LOW Table_GKOSrefToLCDcode	;Get low 8 bits of address
	addwf	GKOSrefshift,F		;Offset, do an 8-bit add operation
	movlw	HIGH Table_GKOSrefToLCDcode	;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_GKOSrefToLCDcode ;call table on another Page
	movwf	scpointer		;save scpointer (LCD character code now)
				;calling FIN/SWE version Table on Page 3
	movlw	HIGH GKOSrefToLCDcode ;Make sure PCLATH is pointing to this Page (0)
	movwf	PCLATH
	return



ScPointerToScancode
;DELETED
	return
;	;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
	return ; 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
	return ; 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)

;********************* IR RECEPTION ***********************************
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


;****************** IR TRANSMISSION *********************************

;**********************
SendChord
	movf	finalchord,w	; Sends finalchord through IR link
SendChord_W			;Enter here if only W contents will be sent
	movwf	TEMPX		;TEMPX = byte to send (6 bits only, bit0 first)
	movlw	d'6'
	movwf	bitcounter	;set counter for 6 bits
SendChord_a
	btfss	TEMPX,0		;bit0=1?
	goto	SendChord_0	;No

	call	Send_1		;Yes SEND '1'
	rrf	TEMPX,f		;Next bit
	decfsz	bitcounter,f	;All 6 bits sent?
	goto	SendChord_a	;No.
	return			;yes, return
SendChord_0
	call	Send_0		;SEND '0'
	rrf	TEMPX,f		;Next bit
	decfsz	bitcounter,f	;All 6 bits sent?
	goto	SendChord_a	;No.
	return			;Yes, return
;-------------------
SendDevice			;Send Device information
				;(the IR controlled device ID)
	movlw	DEVICE		; Use DEVICE definition in IR TX
	;movf	IRdevice,W	; IRdevice does not have the mouse/kbd bit defined
	movwf	TEMPX
	movlw	d'5'
	movwf	bitcounter	;set counter for 5 bits
SendDevice_a
	btfss	TEMPX,0		;bit0=1?
	goto	SendDevice_0	;No

	call	Send_1		;Yes
	rrf	TEMPX,f		;Next bit
	decfsz	bitcounter,f	;All 5 bits sent?
	goto	SendDevice_a	;No.
	return			;yes, return
SendDevice_0
	call	Send_0
	rrf	TEMPX,f		;Next bit
	decfsz	bitcounter,f	;All 5 bits sent?
	goto	SendDevice_a	;No.
	return			;Yes, return

;****************************************************************
SendStart		;gap T (550us), pulse 4T (2200us) 
	bcf	IRTXDATA
	call	DelayT
			;19 cycles per T -> 35.7kHz (19.5 => 36kHz)
			;One cycle: 14us high + 14us low
	movlw	d'78'	;**<78<=Oscilloscope** ;set cycle counter to 4T = 4 x 19.5 = 78
	movwf	temp01	;78 x 28us = 2184 (16us missing) 
	goto	SendPulse
;-----------
Send_1			;gap T (550us), pulse 2T (1100us)
	bcf	IRTXDATA
	call	DelayT
			;19 cycles per T -> 35.7kHz
			;One cycle: 14us high + 14us low
	movlw	d'43';**<43<=Oscilloscope**	;set cycle counter to 2T = 2 x 19 = 38
	movwf	temp01	;38 x 28us = 1064us (36us missing)
	goto	SendPulse
;----------------------
Send_0			;gap T (550us), pulse T (550us)
	bcf	IRTXDATA
	call	DelayT
			;19 cycles per T -> 35.7kHz
			;One cycle: 14us high + 14us low 
	Delay	d'10'	;the missing 18us - 8us for program lines calling
	movlw	d'22';**<22<=Oscilloscope**  ;set cycle counter to T = 1 x 19 = 19
	movwf	temp01	;19 x 28us = 532us (18us missing)
	goto	SendPulse
;-----------------------
	;This sets the Carrier Frequency! Adjusted by Oscilloscope. Do not change!
SendPulse	;Common procedure to send n cycles (n = temp01)
	bsf	IRTXDATA	;1
	Delay	0x0d; **0x0d>14us<=Oscilloscope** 13 ;1+13 = 14us
	bcf	IRTXDATA	;1
	Delay	0x0a; **0x0a>14us<=Oscilloscope** ;>14us;  ;1+11
	decfsz	temp01,f		;1+1+11
	goto	SendPulse	;1+1+1+11 = 14us
	return

;*******************************************************************
DelayT			;IR pulse Basic time period T = 550us
	Delay	d'200'
	Delay	d'200'
	Delay	d'150';<150
	return
;DelayTplus		;IR pulse data bit check period = 825us
;	Delay	d'200'
;	Delay	d'200'
;	Delay	d'200'
;	Delay	d'200'
;	Delay	d'25'
;	return
;****************************************************************
;SendIRPause24		;Pause between chord packets = 24ms
;	bcf	IRTXDATA
;	movlw	d'24'
;	call	DelayWx1ms
;	return
;------
SendPause		;Pause between chord packets = 10ms
	bcf	IRTXDATA
	movlw	d'10'
	call	DelayWx1ms
	return

;************************* END OF IR RX & TX **********************************


;======================= 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
; FUNCTION DELETED
		return		

;*********************
;PS/2 Keyboard Byte Reception
; FUNCTION DELETED

ByteIn0
		return
ByteIn	
		return
ByteIn1
		return

;==================== PS/2 MOUSE COMMUNICATIONS:
;---------------------------------------------------------------------------------------------
; PS/2 Mouse Byte Transmission
; FUNCTION DELETED
MByteOut		
		return

;***************************************************
;PS/2 Mouse Byte Reception
; FUNCTION DELETED

MByteIn0
		return
MByteIn           
		return
MByteIn1
		return
;======================= COMMON SUBROUTINES ===============================

DelayWx10ms
	movwf	dcount1 	; dcount1 = W
	movlw	0x64
	movwf	dcount2 
	movlw	0x20
	movwf	dcount3 
	decfsz	dcount3,F	; delay of > ((((3 * dcount3)+3)*dcount2)+3*W)
	goto 	$ - 1		;    * instruction cycle time (1us for 4MHz)
	decfsz	dcount2,F
	goto 	$ - 5		; so currently W x 10ms
	decfsz	dcount1,F
	goto 	$ - 9		
	return

;*********************

; Delays 4w+4 cycles (including call,return, and movlw) (0=256) 
Delay_Routine   addlw   -1              ;Precise delays used in I/O 
                btfss   STATUS, Z  
                goto    Delay_Routine 
                return     

;*********************

DelayWx1ms
	movwf	dcount1 	; dcount1 = W
	movlw	0x0a
	movwf	dcount2 
	movlw	0x20
	movwf	dcount3 
	decfsz	dcount3,F	; delay of > ((((3 * dcount3)+3)*dcount2)+3*W)
	goto 	$ - 1		;    * instruction cycle time (1us for 4MHz)
	decfsz	dcount2,F
	goto 	$ - 5		; so currently W x 1ms
	decfsz	dcount1,F
	goto 	$ - 9		
	return

;*******************************************************************

;  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
SerTx
	RETURN	; DISABLE THIS DEBUG FUNCTION
SerTx1
	btfss	PIR1, TXIF	; check if ready
	goto	$-1
	movwf	TXREG		; transmit byte
	return


;----------------
; LCD CODES
;
;	<user RAM>	0x00 - 0x0f
;	<not used>	0x10 - 0x1f
;	sp! " # $ % & '	0x20 - 0x27
;	( ) * + , - . /	0x28 - 0x2f
;	0 1 2... 9	0x30 - 0x39
;	: ; < = > ?	0x3a - 0x3f
;	@ A B C ... O	0x40 - 0x4f
;	P Q R S ... Z	0x50 - 0x5a
;	[ <yen> ] ^ _	0x5b - 0x5f
;	` a b c ... o	0x60 - 0x6f
;	p q r s ... z	0x70 - 0x7a
;	{ | } -> <-	0x7b - 0x7f
;	<laatikko>	0xdb
;	ä		0xe1
;	ü		0xf5
;	ö		0xff
;
;
;----------------
; 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

;********************************************************************************

SLEEP_loop

	decfsz	SLEEPcnt1,f	; 
	return	

	movlw	d'255'
	movwf	SLEEPcnt1

	decfsz	SLEEPcnt2,f	; 
	return			;

	movlw	d'255'
	movwf	SLEEPcnt2

	decfsz	SLEEPcnt3,f	; 
	return	

	movlw	SLEEPdelay	; This defines the ilde time before going to sleep
	movwf	SLEEPcnt3	; 1 => 3 seconds  


;	decfsz	SLEEPcnt3,f
;	return	

	; Clear all lines to LCD
	; - bus lines are in input state already
	bcf	LCD_RS
	bcf	LCD_RW
	bcf	LCD_E

	bcf	LCD_power	; turn off LCD and IR receiver power

	; let IR input settle before sleep
	movlw		d'255'		;1/4 sec DELAY
	call		DelayWx1ms		

	movlw		d'255'		;1/4 sec DELAY
	call		DelayWx1ms

	; Define RB6 as output for sleep period because
	; it is pulled low by the IR receiver and would
	; cause the wakeup.

	bsf	STATUS,RP0      ; change to Register bank 1
	bcf	STATUS,RP1	;           ===============
	movlw	b'00111111'	; binary value, 1 bit per port bit
	movwf	TRISB		; RB0-RB6 set to digital inputs, GKOS keys + IR data in
	bcf	STATUS,RP0	; change back to Register bank 0
				;                ===============

;	bcf	PORTB,6		; Pin RB6 = 0 (same as IR data from IR receiver)

	movlw		d'255'		;1/4 sec DELAY
	call		DelayWx1ms		

	movlw		d'255'		;1/4 sec DELAY
	call		DelayWx1ms		

	movlw		d'255'		;1/4 sec DELAY
	call		DelayWx1ms		

	movlw		d'255'		;1/4 sec DELAY
	call		DelayWx1ms		


	bcf	INTCON, RBIF	; Clear Port B interrupt flag (just to make sure)

	;bcf	ADCON0,ADON	; turn off D/A converter to save power

	SLEEP
	nop

	; *** ROUTINES for wakeup:

	; Change 'IR data in' back to input
	bsf	STATUS,RP0      ; change to Register bank 1
	bcf	STATUS,RP1	;           ===============
	movlw	b'01111111'	; binary value, 1 bit per port bit
	movwf	TRISB		; RB0-RB6 set to digital inputs, GKOS keys + IR data in
	bcf	STATUS,RP0	; change back to Register bank 0
				;                ===============



	; Read port RB
	movf	PORTB,W		; Read GKOS chord into W

	; Clear flag bit RBIF
	bcf	INTCON, RBIF	; 

	; ***

	bsf	LCD_power	; turn back on LCD power

	; Delay 1s for key release (4 x 255ms)

	;bsf	ADCON0,ADON	; turn back on D/A converter

	movlw		d'255'		;1/4 sec DELAY
	call		DelayWx1ms		

	; call	SetMouseBias	; Initialize TrackPoint mouse bias voltage
				; to provide 1.8V at Yin when mouse is idle

	; INITIALIZE LCD
	; parameters
	bcf	LCD_E
	clrf	LCD_DDaddress	; Display Data RAM address
	clrf	LCD_CGaddress	; Character Generator RAM address
	bcf	LCD_edge	; Display window edge not passed.

	bsf	LCD_power	; Turn on LCD and IR receiver power

	; Wait 1 seconds for the LCD to start
	movlw	d'100'
	call	DelayWx10ms

	movlw	HIGH LCD_set	; Get high 5 bits of address
	movwf	PCLATH		; Next Page...
	call	LCD_set		; Init procedure
	movlw	HIGH SLEEP_loop	; Make sure PCLATH is pointing to this Page (0)
	movwf	PCLATH

	movlw		d'255'		;1/4 sec DELAY
	call		DelayWx1ms		

	return





;=== KEYBOARD AS MOUSE operation ====
; FUNCTION DELETED
KeyboardMouse
	return

;********************************************************************************
;===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
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
; 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


;------

	; Disacard small values 1...3 (NOT DONE)
	



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

;=============================================================
; second time for this page
DelayWx1ms2
	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

;========================================================
;               LCD initialize
;========================================================

LCD_set
	; Set LCD parameters


	; == 8-bit mode ==
	bsf	Eight_bit_mode

	movlw	0x30		; 
	call	LCD_write_ctrl	; Function set command

	movlw	d'5'		; 5 ms delay after Func set cmd
	call	DelayWx1ms2	; Delay.

	movlw	0x30		; 
	call	LCD_write_ctrl	; Function set command

	movlw	d'1'		; 1 ms (> 0.1 ms) delay after Func set cmd
	call	DelayWx1ms2	; Delay.

	movlw	0x30		; 
	call	LCD_write_ctrl	; Function set command

	bsf	LCD_busycheck	; Busy flag can be checked after this point

	movlw	0x20		; Set LCD 4-bit mode
	call	LCD_write_ctrl	; Function set command

	; == 4-bit mode ==
	bcf	Eight_bit_mode

	movlw	0x28		; Set 4-bit mode, 2-line display and 5x7 char font
	call	LCD_write_ctrl	; Function set 001D  N F x x (N=lines, F=font)
				; D= data length, 1=8 bits, 0=4 bits
				; N=0 1-line disp, N=1 2-line disp
				; F=0 5x7 dots, F=1 5x10 dots
				; 0010 1000
 
	movlw	0x08		; Display OFF
	call	LCD_write_ctrl	; Function set

	movlw	0x01		; Clear display
	call	LCD_write_ctrl	; Function set

	movlw	0x06		; Entry mode set: I/D = increment, S=0 shift right
	call	LCD_write_ctrl	; Function set 0000  0 1 I/D S (0000 0110)

	movlw	0x0f		; Diplay ON: D ON/OFF, C show cursor, B blink
	call	LCD_write_ctrl	; Function set 0000  1 D C B (0000 1111)

;	movlw	0x80		; Set DD RAM address (to be able to read DD address)
;	call	LCD_write_ctrl	; Function set

	return

;=======================================================================
	; Send code to LCD (code= scancode) ddddddd <<to search for
;=======================================================================

LCD_proc

;-------- (TEMPX &)scpointer is the character code from the table -----


	; display is used => initialize SLEEP counters
	movlw	d'255'
	movwf	SLEEPcnt1
	movwf	SLEEPcnt2
	movlw	SLEEPdelay	; This defines the ilde time before going to sleep
	movwf	SLEEPcnt3  	; 1 => 3 sec


;--------------------- SEND THE LCD CODES TO LCD UNIT ----------------------
;TEMPX:
;--- LCD codes 0xa0 - 0xaa and 0xb0 - 0xb9 are indications for commands etc.
	
	movf	TEMPX,W
	andlw	0xf0		; Commands, not characters?
	xorlw	0xa0		;= 0xay?
	btfsc	STATUS,Z	;is zero bit set in Status Register?
	goto	OtherCommands	;Yes.
				;No.
	movf	TEMPX,W
	andlw	0xf0		; Commands, not characters?
	xorlw	0xb0		;= 0xby?
	btfsc	STATUS,Z	;is zero bit set in Status Register?
	goto	OtherCommands	;Yes.
				;No.
;----------------------------------------------------------
	movf	TEMPX,W
	call	SerTx2		;debug


;---------
	; Bottom or top line on the LCD?

	btfss	RecChar		; Coming from IR?
	goto	LCD_lowerline	; No. From local GKOS keyboard.

				; Yes. == From IR, top line ==
	btfsc	RecCharPrev	; RecChar=1. Same line as before?
	goto	LCD_linesX	; Yes. No action.
	bsf	RecCharPrev	; No. Update value.
				; Change to Top line.

	bcf	LCD_DDaddress,6	; Clear the bit that defines the line (x0xx xxxx)
	movf	LCD_DDaddress,W	; put in W
	ADDLW	0x80		; Set DD RAM address too. (Cmnd: 1aaa aaaa)
	call	LCD_write_ctrl	; Function set. Move to Top Line.
	goto	LCD_linesX

LCD_lowerline			; == From local keyboard, bottom line ==
	btfss	RecCharPrev	; RecChar=0. Same line as before?
	goto	LCD_linesX	; Yes. No action.
	bcf	RecCharPrev	; No. Update value.
				; Change to Bottom line.

	bsf	LCD_DDaddress,6	; Set the bit that defines the line (x1xx xxxx)
	movf	LCD_DDaddress,W	; put in W
	ADDLW	0x80		; Set DD RAM address too. (Cmnd: 1aaa aaaa)
	call	LCD_write_ctrl	; Function set. Move to Bottom line.

LCD_linesX
;----------

	movf	scpointer,W	; Get the display character code
	call	LCD_write_disp

	call	LCD_incaddr

	return
;-----
BusyLoop
	btfss	LCD_busycheck	; Should LCD busy flag be already checked?
	goto	BusyLoopX	; No.
BusyLoopIN			; Yes.
	; test if LCD busy...	; (uses TEMPX)
	call	LCD_read_ctrl	; LCD busy? read busy flag and address
	btfsc	LCD_busy	; no
	goto	BusyLoopIN	; yes, loop back
	;call	LCD_read_ctrl	; Read second time in a row to get proper DD address
	;movwf	LCD_DDaddress	; Save Display Data RAM address (busy bit=0)
BusyLoopX
	return
;-----

LCD_write_disp
	; data in W
	movwf	TEMPY		; save data (7654 3210) in TEMPY
	call	BusyLoop	; Wait until LCD not busy (uses TEMPX)
	bsf	LCD_RS		; Select display data register (RS=1)
LCD_write
	bcf	LCD_RW		; Select Write operation

	bsf	STATUS,RP0      ; == BANK 1 == change to register bank 1
	movlw	b'11000011'	; binary value, 1 bit per port bit
	movwf	TRISA		; RA2-5  set to outputs (2 spare pins, R0-1)
	bcf	STATUS,RP0	; == BANK 0 == change to register bank 0

	; test if LCD busy...
	movlw	d'1' 		; 1 ms delay instead (TEMPORARY)
	call	DelayWx1ms2	; Delay.

	; Send first nibble (D7 D6 D5 D4)
	movf	TEMPY,W		; Get data to send
	movwf	TEMPX		; 7654 3210 in TEMPX, data
	rrf	TEMPX,f		; Shift for port pins 2-5
	rrf	TEMPX,W		;>xx76 5432
	ANDLW	b'00111100'	; 0076 5400
	movwf	PORTA
	
	bsf	LCD_E		; Enable operation
	movlw	d'1'		; 1 ms delay
	call	DelayWx1ms2	; Delay.
	bcf	LCD_E		

	btfsc	Eight_bit_mode	; LCD 8-bit mode ON?
	goto	EightBitReturn	; Yes. no more sending

	; Send second nibble (D3 D2 D1 D0)
				; 7654 3210
	rlf	TEMPY,f		; Shift for port pins 2-5
	rlf	TEMPY,W		;>5432 10xx
	;movf	TEMPY,W		; 
	ANDLW	b'00111100'	; 0032 1000
	movwf	PORTA
	bsf	LCD_E		; Enable operation
	movlw	d'1'		; 1 ms delay
	call	DelayWx1ms2	; Delay.
	bcf	LCD_E		

EightBitReturn
	bsf	STATUS,RP0      ; == BANK 1 == change to register bank 1
	movlw	b'11111111'	; binary value, 1 bit per port bit
	movwf	TRISA		; RA3-5  set to inputs (2 spare pins, R0-1)
	bcf	STATUS,RP0	; == BANK 0 == change to register bank 0

	return			; Back to MainLoop


LCD_write_ctrl
	; data in W
	movwf	TEMPY		; save data (7654 3210) in TEMPY
	call	BusyLoop	; Wait until LCD not busy
	bcf	LCD_RS		; Select control data register (RS=0)
	goto	LCD_write


;------------read LCD

LCD_read_disp			; Read data from Char Generator or Disp Data RAM
	bsf	LCD_RS		; Select display data register (RS=1)
LCD_read
	bsf	LCD_RW		; Select Read operation

	; Read first nibble (D7 D6 D5 D4)

	bsf	LCD_E		; Enable operation
	movlw	d'1'		; 1 ms delay
	call	DelayWx1ms2	; Delay.

	movf	PORTA,W		; Read port A xx76 54xx
	movwf	TEMPX		; save into TEMPX 0076 5400
	rlf	TEMPX,f		;
	rlf	TEMPX,W		; 7654 xxxx
	ANDLW	b'11110000'	; 7654 0000
	movwf	TEMPX		; 7654 0000 <<
	
	bcf	LCD_E		; 

	movlw	d'1'		; 1 ms delay (might be smaller)
	call	DelayWx1ms2	; Delay.

	; Read second nibble (D3 D2 D1 D0)

	bsf	LCD_E		; Enable operation
	movlw	d'1'		; 1 ms delay
	call	DelayWx1ms2	; Delay.

	movf	PORTA,W		; Read port A
	movwf	Tmp2		; xx32 10xx
	rrf	Tmp2,f
	rrf	Tmp2,W		; xxxx 3210
	ANDLW	b'00001111'	; 0000 3210

				; Combine nibbles:
	ADDWF	TEMPX,f		; 7654 3210 byte in TEMPX
	movf	TEMPX,W		; and in W

	bcf	LCD_busy	; LCD busy?
	btfsc	TEMPX,7		; busy bit = DB7
	bsf	LCD_busy	; yes, busy
				; not busy
	bcf	LCD_E		
				; Received byte is in TEMPX and W
	return			; Back to MainLoop

LCD_read_ctrl			; read busy flag and address
	bcf	LCD_RS		; Select control data register (RS=0)
	goto	LCD_read

;	RS R/W
;	 0  1	read busy flag and address
;	 1  1	read data from CG or DD RAM

;			end of	end of  start of
;		start	window	line    line		end
;	decimal	0	15	39   | 0		39
; Line 1	0x00	0x0f	0x27 | 0x00		0x27
; Line 2	0x40	0x4f	0x67 | 0x40		0x67
;	decimal	64	79	103  | 0		103


LCD_incaddr	; first line   0- 39 (0x00-0x27)
		; second line 64-104 (0x40-0x67)
	btfsc	LCD_DDaddress,6	; Second line in use?
	goto	SecondLineInc	; Yes.
	movlw	d'15'		; No. Is this the right edge of the disp area?
	XORWF	LCD_DDaddress,W	;
	btfsc	STATUS,Z	; ZERO set? EQUAL?
	bsf	LCD_edge	; Yes. Edge passed now.
	incf	LCD_DDaddress,f	; increment DD address
	btfss	LCD_edge	; LCD edge passed?
	goto	LCD_incaddrX ; No.
	movlw	0x18		; Yes. Shift display left. 0001 1000
	call	LCD_write_ctrl	; Function set

	movlw	d'40' ;d'41'		; Is this past the end of first line?
	XORWF	LCD_DDaddress,W	;
	btfss	STATUS,Z	; ZERO set? EQUAL?
	return			; No.
	clrf	LCD_DDaddress	; Yes. Stay on first line. First position.
	movlw	0x80		; Yes. Set DD RAM address = 0x00
	call	LCD_write_ctrl	; Function set
	return
	; second line in use
SecondLineInc
	movlw	d'79'		; No. Is this the right edge of the disp area?
	XORWF	LCD_DDaddress,W	;
	btfsc	STATUS,Z	; ZERO set? EQUAL?
	bsf	LCD_edge	; Yes. Edge passed now.
	incf	LCD_DDaddress,f	; increment DD address
	btfss	LCD_edge	; LCD edge passed?
	goto	LCD_incaddrX ; No.
	movlw	0x18		; Yes. Shift display left. 0001 1000
	call	LCD_write_ctrl	; Function set

	movlw	d'104'		; Is this past the end of second line?
	XORWF	LCD_DDaddress,W	;
	btfss	STATUS,Z	; ZERO set? EQUAL?
	return			; No.
	movlw	0x40		; Yes. Stay on second line. First position.
	movwf	LCD_DDaddress	; 
	movlw	0xc0		; Yes. Set DD RAM address = 0x40
	call	LCD_write_ctrl	; Function set
	return

LCD_incaddrX
	return

LCD_decaddr
	btfsc	LCD_DDaddress,6	; Second line in use?
	goto	SecondLineDec	; Yes.

	; First line in use
	movlw	d'0'		; Is this first position of first line?
	XORWF	LCD_DDaddress,W	;
	btfsc	STATUS,Z	; ZERO set? EQUAL?
	goto	LCD_decaddr_1	; Yes. Stay on first line, position 39 next
	decf	LCD_DDaddress,f	; No. Just update DD address
	return
LCD_decaddr_1	; 39 <- 0
	movlw	d'39'		; last position of first line
	movwf	LCD_DDaddress
	movlw	0xa7		; Yes. Set DD RAM address = 39 => 0x80 + 0x27 = 0xa7
	call	LCD_write_ctrl	; Function set	
	return
	; Second line in use
SecondLineDec	; 103 <- 64
	movlw	d'64'		; Is this first position of second line?
	XORWF	LCD_DDaddress,W	;
	btfsc	STATUS,Z	; ZERO set? EQUAL?
	goto	LCD_decaddr_1s	; Yes. Stay on second line, position 39+64 next
	decf	LCD_DDaddress,f	; No. Just update DD address
	return
LCD_decaddr_1s
	movlw	d'103'		; last position of second line
	movwf	LCD_DDaddress	
	movlw	0xe7		; Yes. Set DD RAM address = 103 => 0x80 + 0x67 = 0xe7
	call	LCD_write_ctrl	; Function set.
	return

; lllllllll
;--------------------

OtherCommands

	; ADD HERE COMMANDS
	; how to treat Space, BackSpace, ENTER etc?

	movlw	0xa8		; Space?
	xorwf	TEMPX,W	;
	bnz	$ + 2		; No.	
	goto	LCD_Space	; Yes.

	movlw	0xa4		; BackSpace?
	xorwf	TEMPX,W	;
	bnz	$ + 2		; No.	
	goto	LCD_BackSpace	; Yes.


	movlw	0xa5		; Left Arrow?
	xorwf	TEMPX,W	;
	bnz	$ + 2		; No.	
	goto	LCD_LeftArrow	; Yes.

	movlw	0xa9		; Right Arrow?
	xorwf	TEMPX,W	;
	bnz	$ + 2		; No.	
	goto	LCD_RightArrow	; Yes.

	movlw	0xa0		; Up Arrow?
	xorwf	TEMPX,W	;
	bnz	$ + 2		; No.	
	goto	LCD_UpArrow	; Yes.

	movlw	0xa1		; Down Arrow?
	xorwf	TEMPX,W	;
	bnz	$ + 2		; No.	
	goto	LCD_DownArrow	; Yes.

	movlw	0xb0		; Enter?
	xorwf	TEMPX,W	;
	bnz	$ + 2		; No.	
	goto	LCD_Enter	; Yes.

	movlw	0xb3		; Delete?
	xorwf	TEMPX,W	;
	bnz	$ + 2		; No.	
	goto	LCD_Delete	; Yes.

	movlw	0xaa		; Word Right?
	xorwf	TEMPX,W	;
	bnz	$ + 2		; No.	
	goto	LCD_ShiftLeft	; Yes.

	movlw	0xa6		; Word Left?
	xorwf	TEMPX,W	;
	bnz	$ + 2		; No.	
	goto	LCD_ShiftRight	; Yes.

	movlw	0xb1		; Tab?
	xorwf	TEMPX,W	;
	bnz	$ + 2		; No.	
	goto	LCD_Tab		; Yes.




	return
;-----------code on the list: ----------
;       0xa0 ;Arrow up -- NAVIGATING
;       0xa1 ;Arrow down
;       0xa2 ;PgUp
;       0xa3 ;PgDn
;       0xa4 ;Backspace
;       0xa5 ;Arrow left
;       0xa6 ;Word left
;       0xa7 ;Home
;       0xa8 ;Space /50 
;       0xa9 ;Arrow right
;       0xaa ;Word right
;       0xab ;End
;controls
;       0xb0 ;Enter
;       0xb1 ;Tab
;       0xb2 ;Esc 
;       0xb3 ;Del
;       0xb4 ;Ins
;       0xb5 ;Shift (RIGHT)
;       0xb6 ;SYMB /60 (0xe8) GKOS only
;       0xb7 ;123-abc  (0xe9) GKOS only
;       0xb8 ;Ctrl (LEFT)
;       0xb9 ;Alt /64
;--------------------------------------------


LCD_Space
	movlw	0xa0
	call	LCD_write_disp	; show space
	call	LCD_incaddr
	return

LCD_BackSpace
	movlw	b'00010000'	; Left Arrow
	call	LCD_write_ctrl
	movlw	0xa0		; Space
	call	LCD_write_disp	

	call	LCD_decaddr

	movlw	b'00010000'	; Left Arrow
	call	LCD_write_ctrl
	btfss	LCD_edge
	return
	movlw	b'00011100'	; Display right
	call	LCD_write_ctrl
	return

LCD_LeftArrow
	movlw	b'00010000'	; Cursor left
	call	LCD_write_ctrl
	call	LCD_decaddr
	movlw	b'00011100'	; Display right
	call	LCD_write_ctrl
	return

LCD_RightArrow
	movlw	b'00010100'	; Cursor right
	call	LCD_write_ctrl
	call	LCD_incaddr
	return

LCD_UpArrow
	bcf	LCD_edge
	clrf	LCD_DDaddress
	movlw	b'10000000'	; First line first location
	call	LCD_write_ctrl
	return

LCD_DownArrow
	bcf	LCD_edge
	clrf	LCD_DDaddress
	movlw	b'11000000'	; Second line first location
	call	LCD_write_ctrl
	return

LCD_Enter
	movlw	b'00000001'	; Clear display
	call	LCD_write_ctrl
	;movlw	0x06		; Change Entry mode back to 0000 0110 (01 I/D S)
	;call	LCD_write_ctrl	; S=0: the whole display is not shifted left 0x07
	bcf	LCD_edge	; LCD edge flag: no disp shift needed yet
	movlw	0x80		; Set DD RAM address to original position
	call	LCD_write_ctrl	; Function set
	clrf	LCD_DDaddress	; Update DD address
	bcf	RecChar		; Update line flag also
	return

LCD_Delete
	movlw	0xa0		; Space
	call	LCD_write_disp	
	movlw	b'00010000'	; Left Arrow
	call	LCD_write_ctrl
	return

LCD_SHIFT
	;----
	return

LCD_ShiftRight
	movlw	b'00011100'
	call	LCD_write_ctrl
	return

LCD_ShiftLeft
	movlw	b'00011000'
	call	LCD_write_ctrl
	return

LCD_Tab	;test moving to second line
	; better way test/change bit6 in LCD_DDaddress
	movlw	0x40		; Toggle the bit that defines the line
	XORWF	LCD_DDaddress,W	; in W
	movwf	LCD_DDaddress	; in file too
	ADDLW	0x80		; Yes. Set DD RAM address too. (Cmnd: 1aaa aaaa)
	call	LCD_write_ctrl	; Function set

	return




;------------------ LCD INFORMATION: --------------
; Physical LCD data lines DB7, DB6, DB5, DB4 are used in 4-bit mode
; (map these to PORTA D5, D4, D3, D2)

;
; Write control data, RS=0
; ========================
; Function set	 0x2X	set 4-bit mode (only one transmission, 8-bit mode still valid)
; Function set	 28	set 4-bit mode, 2-line display and 5x7 char font (4-bit mode is on)
; Display ON	 0e	turn on display and cursor
; Entry mode set 06	Set mode to increment address by one and shift cursor
;
; Move cursor	 c0	moves cursor and RAM address to beginning of second line
; Move cursor	 80	moves cursor and RAM address to original position (beginning)
;
; Write display data, RS=1
; ========================
; Write 'L'	 4c
;
; Read data
; =========
; RS=0: Read busy flag (BF=D7) and CGRAM/DDRAM address (D6-0), BF=0: not busy
; RS=1: Reads data from CGRAM or DDRAM.
;==============================================================================




;-------------------------------------------------------------------------------



;______________________end of Page1 0000h-07FFf_________________________________
;
;===============================================================================
;_____________________ Page2 1000h-17FFh (spare)________________________________
;
;	     org	0x1800	;Start of Program Memory Page 3


;----------------------------
; spare room for program code
;----------------------------



;______________________end of Page2 1000h-17FFf____________________________________
;
;=================================================================================
;_____________________ Page3 1800h-1FFFh (spare)___________________________________


;===================== 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) 
;
; Two tables are used to convert the chord all the way to scan codes:
; Table_ChordToRef => Table_GKOSrefToScPointer => Table_ScanCodes_abc
;
;
;===========================================================================;

	     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
;

Table_GKOSrefToLCDcode
            movwf	 PCL
;---------------- abc mode ------------------------
            retlw        0x61 ;a /0	SYMB mode table is 128 steps down.
            retlw        0x62 ;b	Add 128 to GKOSref if using SYMB table.
            retlw        0x63 ;c
            retlw        0x64 ;d     Same goes for 123-mode but GKOSref values
            retlw        0x65 ;e	but add only 64 to GKOSref	
            retlw        0x66 ;f
            retlw        0x67 ;g	SHIFT can be only applied to GKOSref
            retlw        0x68 ;h	values 0-30 (a-ö)???
            retlw        0x69 ;i
            retlw        0x6a ;j /10
            retlw        0x6b ;k
            retlw        0x6c ;l
            retlw        0x6d ;m
            retlw        0x6e ;n
            retlw        0x6f ;o
            retlw        0x70 ;p
            retlw        0x71 ;q
            retlw        0x72 ;r
            retlw        0x73 ;s
            retlw        0x74 ;t /20
            retlw        0x75 ;u
            retlw        0x76 ;v
            retlw        0x77 ;w
            retlw        0x78 ;x
            retlw        0x79 ;y
            retlw        0x7a ;z
            retlw        0xf5 ;u (umlaut)
            retlw        0x61 ;å <>
            retlw        0xe1 ;ä
            retlw        0xef ;ö /30

            retlw        0x2e  ; .
            retlw        0x2c  ; ,
            retlw        0x21 ; !
            retlw        0x3f ; ?
            retlw        0x2d  ; - 35
            retlw        0x27  ; '
            retlw        0x2f ; /
            retlw        0xdb ; \ <>
            retlw        0xdb  ; ¨ <>
            retlw        0xdb ; ~ /40 <>
            retlw        0xdb ; ^ <>
		;ALL MODES
            retlw        0xa0 ;Arrow up -- NAVIGATING
            retlw        0xa1 ;Arrow down
            retlw        0xa2 ;PgUp
            retlw        0xa3 ;PgDn
            retlw        0xa4 ;Backspace
            retlw        0xa5 ;Arrow left
            retlw        0xa6 ;Word left
            retlw        0xa7 ;Home
            retlw        0xa8 ;Space /50 
            retlw        0xa9 ;Arrow right
            retlw        0xaa ;Word right
            retlw        0xab ;End
		;controls
            retlw        0xb0 ;Enter
            retlw        0xb1 ;Tab
            retlw        0xb2 ;Esc 
            retlw        0xb3 ;Del1
            retlw        0xb4 ;Ins
            retlw        0xb5 ;Shift (RIGHT)
            retlw        0xb6 ;SYMB /60 (0xe8) GKOS only
            retlw        0xb7 ;123-abc  (0xe9) GKOS only
            retlw        0xb8 ;Ctrl (LEFT)
            retlw        0xb9 ;Alt /64
         ;123 mode, add 64 to GKOS ref.num
;------------------ 123 mode -------------------------
            retlw        0x31 ;1 /65
            retlw        0x32 ;2
            retlw        0x33 ;3
            retlw        0x34 ;4
            retlw        0x35 ;5
            retlw        0x36 ;6 /70
            retlw        0x30 ;0
            retlw        0x37 ;7
            retlw        0x38 ;8
            retlw        0x39 ;9
            retlw        0x23 ; #
            retlw        0xdb ; ½ <>
            retlw        0x26 ; &
            retlw        0x40 ; @
            retlw        0x2b  ; +
            retlw        0x25 ; % /80
            retlw        0x3d ; =
            retlw        0x5c  ; Y (yen) just 'y'
            retlw        0x2a ; *
            retlw        0xdb ; € <>
            retlw        0x24 ; $
            retlw        0xdb ; £ <>
            retlw        0x28 ; (
            retlw        0x5b ; [
            retlw        0x3c  ; <
            retlw        0x7b ; { /90
            retlw        0x29 ; )
            retlw        0x5d ; ]
            retlw        0x3e ; >
            retlw        0x7d ; }
; 
			;Down from here the same as in abc mode...
            retlw        0x2e  ; .
            retlw        0x2c  ; ,
            retlw        0x21 ; !
            retlw        0x3f ; ?
            retlw        0x2d  ; -
            retlw        0x27  ; '  /100
            retlw        0x2f ; /
            retlw        0xdb ; \ <>
            retlw        0xdb  ; ¨ <>
            retlw        0xdb ; ~ /40 <>
            retlw        0xdb ; ^ <>
		;ALL MODES
            retlw        0xa0 ;Arrow up -- NAVIGATING
            retlw        0xa1 ;Arrow down
            retlw        0xa2 ;PgUp
            retlw        0xa3 ;PgDn
            retlw        0xa4 ;Backspace  /110
            retlw        0xa5 ;Arrow left
            retlw        0xa6 ;Word left
            retlw        0xa7 ;Home
            retlw        0xa8 ;Space /50 
            retlw        0xa9 ;Arrow right
            retlw        0xaa ;Word right
            retlw        0xab ;End
		;controls
            retlw        0xb0 ;Enter
            retlw        0xb1 ;Tab
            retlw        0xb2 ;Esc /120
            retlw        0xb3 ;Del1
            retlw        0xb4 ;Ins
            retlw        0xb5 ;Shift (RIGHT)
            retlw        0xb6 ;SYMB     (0xe8) GKOS only
            retlw        0xb7 ;123-abc  (0xe9) GKOS only
            retlw        0xb8 ;Ctrl (LEFT)
            retlw        0xb9 ;Alt

;--------------------- SYMB mode ----------------------------
            retlw        0x31 ;1
            retlw        0x32 ;2
            retlw        0x33 ;3 /130
            retlw        0x34 ;4
            retlw        0x35 ;5
            retlw        0x36 ;6
            retlw        0x30 ;0
            retlw        0x37 ;7
            retlw        0x38 ;8
            retlw        0x39 ;9
            retlw        0x23 ; #
            retlw        0xdb ; ½ <>
            retlw        0x26 ; & /140
            retlw        0x40 ; @
            retlw        0x2b  ; +
            retlw        0x25 ; %
            retlw        0x3d ; =
            retlw        0x5c  ; Y (yen) just 'y'
            retlw        0x2a ; *
            retlw        0xdb ; € <>
            retlw        0x24 ; $
            retlw        0xdb ; £ <>
            retlw        0x28 ; (  /150
            retlw        0x5b ; [
            retlw        0x3c  ; <
            retlw        0x7b ; {
            retlw        0x29 ; )
            retlw        0x5d ; ]
            retlw        0x3e ; >
            retlw        0x7d ; }
	 ;symbols only in SYMB mode (GKOSref 95-105):
            retlw        0x3a ; : /95
            retlw        0x3b ; ; 
            retlw        0xdb ;inverted ! <> /160
            retlw        0xdb ;inverted ? <>
            retlw        0x5f ; _
            retlw        0x22 ; " 
            retlw        0x27  ; ´ <> apostrophe instead
            retlw        0x60 ; `
            retlw        0x7c ; | 
            retlw        0xdb  ; § <>
            retlw        0xdb ; ¤ <>
		;ALL MODES
            retlw        0xa0 ;Arrow up -- NAVIGATING
            retlw        0xa1 ;Arrow down /170
            retlw        0xa2 ;PgUp
            retlw        0xa3 ;PgDn
            retlw        0xa4 ;Backspace
            retlw        0xa5 ;Arrow left
            retlw        0xa6 ;Word left
            retlw        0xa7 ;Home
            retlw        0xa8 ;Space 
            retlw        0xa9 ;Arrow right
            retlw        0xaa ;Word right
            retlw        0xab ;End  /180
		;controls
            retlw        0xb0 ;Enter
            retlw        0xb1 ;Tab
            retlw        0xb2 ;Esc 
            retlw        0xb3 ;Del1
            retlw        0xb4 ;Ins
            retlw        0xb5 ;Shift (RIGHT)
            retlw        0xb6 ;SYMB     (0xe8) GKOS only
            retlw        0xb7 ;123-abc  (0xe9) GKOS only
            retlw        0xb8 ;Ctrl (LEFT)
            retlw        0xb9 ;Alt /190
;------------------- 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
;
; This table is LCD application specific and used always when SHIFT
; is on and GKOSref = 1...30 
;---------------- abc mode ------------------------
            retlw        0x41 ;A /181	SHIFT mode in on and GKOSref = 1...30
            retlw        0x42 ;B	Add 180 to GKOSref if using SYMB table.
            retlw        0x43 ;C
            retlw        0x44 ;D
            retlw        0x45 ;E
            retlw        0x46 ;F
            retlw        0x47 ;G
            retlw        0x48 ;H
            retlw        0x49 ;I
            retlw        0x4a ;J
            retlw        0x4b ;K ETC.
            retlw        0x4c ;l
            retlw        0x4d ;m
            retlw        0x4e ;n
            retlw        0x4f ;o
            retlw        0x50 ;p
            retlw        0x51 ;q
            retlw        0x52 ;r
            retlw        0x53 ;s
            retlw        0x54 ;t
            retlw        0x55 ;u
            retlw        0x56 ;v
            retlw        0x57 ;w
            retlw        0x58 ;x
            retlw        0x59 ;y
            retlw        0x5a ;z
            retlw        0xf5 ;u (umlaut) THESE ARE NOT YET OK
            retlw        0x41 ;å <>
            retlw        0xe1 ;ä
            retlw        0xef ;ö
;------------ END OF SHIFT TABLE ------------




	; Serial port Message example:

;	movwf	PCL
;	retlw	'o'	;ASCII 'o'
;	retlw	'k'	;ASCII 'k'
;	retlw	'!'	;ASCII '!'
;	retlw	d'0'	;decimal zero


; ==========START OF MEMORY PAGE 3 KEYBOARD TABLE====================
;
;
;	    org		 0x1A00	; later in program Memory Page 3, after FIN/SWE table

	END                     ; directive 'end of program'

