'jleblanc 3.18.06
'this code writes a keyboard input out to Xterm and the LCD
'this new version allows you to use the shift key
'uses code from Daryl Owen 7/11/00 (see my website for link)
'for my connector: 
    'red to ground
    'white to power
    'black to C4
    'yellow to C5
'See just bellow for LCD setup

DEFINE OSC 20

'SETUP LCD
    'This setup will tell PBP a 2-line LCD is connected in 4-bit 
    'mode with the data bus on the top 4 bits of PORTB, Register 
    'Select on PORTB.1, and Enable on PORTB.0.
    'Data Bits go like: 3>B.7, 2>B.6, 1>B.5, 0>B.4
	DEFINE LCD_DREG	PORTB
	' Set starting Data bit (0 or 4) if 4-bit bus
	DEFINE LCD_DBIT	4
	' Set LCD Register Select port
	DEFINE LCD_RSREG	PORTB
	' Set LCD Register Select bit
	DEFINE LCD_RSBIT	1
	' Set LCD Enable port
	DEFINE LCD_EREG	PORTB
	' Set LCD Enable bit
	DEFINE LCD_EBIT	0
	' Set LCD bus size (4 or 8 bits)
	DEFINE LCD_BITS	4
	' Set number of lines on LCD
	DEFINE LCD_LINES	2
	' Set command delay time in us
	DEFINE LCD_COMMANDUS	2000
	' Set data delay time in us
	DEFINE LCD_DATAUS	50

'Variables used to interface with keyboard
    Keypress VAR BYTE'Keyboard value read from keyboard
    AscKey VAR BYTE'This is used to send key scan data and subroutine controls to other subroutines
    TempReg VAR BYTE'Misc temp register
    Temp2Reg VAR BYTE'Misc temp register
    ShiftReg VAR BIT'Stores the shift key status. 1=shift 0=no shift
    DumpReg VAR BIT'Temp reg for dumping keypress values after a releasecommand
'Variables used with LCD
    CursorLocation VAR BYTE'Cursor Location on LCD
    CursorMin VAR BYTE'Minimum cursor position
    CursorMax VAR BYTE'Maximum cursor position
    CursorLocation=0
    CursorMin=0
    CursorMax=21
'Message array
    i VAR BYTE
    pos VAR BYTE
    Msg VAR BYTE[24]
'initialize
    pos=0
    FOR  i=0 TO 23
        Msg[i]=" "
    NEXT i

SEROUT2 PORTC.6, 16468, ["Starting Up", 10, 13]
LCDOUT $fe, 1   ' Clear screen
LCDOUT "Starting Up"  ' Send Hello Message
PAUSE 1000
LCDOUT $fe, 1   ' Clear screen


Main:
    GOSUB ScanKeyboard'Gets key pressed keycode
    GOSUB BackSpace 'Handles backspacing
    GOSUB ChrtoASCII'Changes keycode into ascii
    GOSUB UpdateXTERM 'Print to the window
    GOSUB UpdateMSG 'Updates Msg array
    GOSUB RenderScreen 'Updates LCD
GOTO Main

ScanKeyboard:
    DumpReg = 0
    DumpKeys:'NOTE
    
    AscKey = 0
    Keypress = 0
    TrisC.5 = 1 : PortC.5 = 1 'Release Clock Line for Com from Keyboard to PIC
    GOSUB ClockCycle'Dumps start bit
    FOR TempReg = 0 TO 7
        GOSUB ClockCycle
        IF PortC.4 = 1 THEN 'Calculates bit value
            LOOKUP TempReg,[1,2,4,8,16,32,64,128],Temp2Reg
            Keypress = Keypress + Temp2Reg'Adds the bit values together
        ENDIF
    NEXT TempReg
    
    GOSUB ClockCycle'Dumps parity bit
    GOSUB ClockCycle'Dumps stop bit
    TrisC.5 = 0 : PortC.5 = 0 'Set Clock Line Low and hold Com from Keyboard to PIC

    IF Keypress = $F0 THEN'If key release command then go again
        DumpReg = 1'Set so that next key will also get dumped
        GOTO DumpKeys'Rerun loop
    ENDIF

    IF Keypress=$58 || Keypress=$12 || Keypress=$59 && DumpReg = 1 THEN'Turn off ShiftReg
        ShiftReg = 0'Sets the Shift Reg for Shift
        AscKey = 255'Will not print anything on LCD
    ENDIF

    IF DumpReg = 1 THEN'If this loop was to dump chr then send a 255 to next
        DumpReg = 0 '???????
        Keypress = 255
    ENDIF

    IF Keypress=$58 || Keypress=$12 || Keypress=$59 THEN'Turn on ShiftReg
        ShiftReg = 1'Sets the Shift Reg for Shift
        AscKey = 255'Will not print anything on LCD
    ENDIF
RETURN

UpdateXTERM:'This will convert the key scan codes to ASCCII
    IF AscKey <> 255 THEN
           SEROUT2 PORTC.6, 16468, [Keypress]
    ENDIF
RETURN

UpdateMSG:'This will convert the key scan codes to ASCCII
    IF AscKey <> 255 THEN
        Msg[pos]=Keypress
        pos=pos+1
        IF pos > 23 THEN pos=23
    ENDIF
RETURN

RenderScreen:
    'Clear Screen
    LCDOUT $fe, 1
        'Render first line
        FOR i=0 TO 11
                LCDOUT  Msg[i]
        NEXT
    'Move to second line
    LCDOUT $fe, $C0
        'Render second line
        FOR i=12 TO 23
                LCDOUT  Msg[i]
        NEXT
RETURN

ClockCycle:'Waits for the clock to cycle from keyboard
    HoldClockLow:
        IF PortC.5 = 0 THEN HoldClockLow
    HoldClockHi:
        IF PortC.5 = 1 THEN HoldClockHi
RETURN

ChrtoASCII:'Converts keycode into ASCII
    IF AscKey <> 255 THEN
        AscKey = 255
        LOOKDOWN Keypress,[69,22,30,38,37,46,54,61,62,70,28,50,33,35,36,43,52,51,67,59,66,75,58,49,68,77,21,45,27,44,60,42,29,34,53,26,41,78,85,93,84,91,76,82,65,73,74],AscKey
        
        IF ShiftReg = 0 THEN
            LOOKUP AscKey,["0123456789abcdefghijklmnopqrstuvwxyz -=|{};',./"],Keypress
        ELSE
            LOOKUP AscKey,[")!@#$%^&*(ABCDEFGHIJKLMNOPQRSTUVWXYZ _+|{}:'<>?"],Keypress
        ENDIF
    ENDIF
RETURN

BackSpace:
    IF Keypress = $66 THEN'Backspace key pressed
        IF pos=23 THEN 
            IF Msg[pos]=" " THEN
                pos=pos-1: Msg[pos]=" "
            ELSE
                Msg[pos]=" "
            ENDIF
        ELSE
            IF pos > 0 THEN 
                pos=pos-1
                Msg[pos]=" "
            ENDIF
        ENDIF
       
        AscKey = 255 'Don't enable further writing
    ENDIF
RETURN