; The Septambic Keyer program began as a collaborative effort between ; Steve Mann and Adam Wozniak, based on Wozniak's "pickey.asm" ; written 1999 May 10, and on Mann's concept of a "multiambic" keyer ; from the 1970s (pentambic) and his desire to get a modern PIC based ; implementation of a multiambic keyer, in this case, one with keycodes ; similar to the BAT keyboard. ; ; Mann and Wozniak met 1999 August 2 for a long drawn out keyer hackfest ; at the University of Toronto, and after many hours of long hacking, ; managed to modify Wozniak's code for use in a septambic keyer. ; ; This hackfest produced a working multikeyer but not all the letters, ; were defined, and only a portion of the total number of keyswitches ; were programmed. However this was a successful proof of concept, ; using a PIC with a multiambic keyer. ; ; During that time the original Wozniak circuit board was modified by ; cutting the traces and connecting it to one of Mann's septambic keyers. ; ; James Fung was also present for a small portion of this original ; hackfest, and made some suggestions, etc., in the coding. ; ; Mann kept in collaboration with Wozniak, and also made this keyer ; project available to students. ; ; One student, Eric Moncrieff, continued where Mann and Wozniak had left off, ; following suggestions from Mann to split the program into separate portions ; to scan the keys and separately lookup the definitions of the keys, and ; separately produce the keycodes, and fixing some of the remaining bugs. ; ; Luke Stras also provided some creative input into this effort, working ; with Moncrief and the rest of us. ; ; The septambic keyer comprises three thumb buttons, designated red, ; grey and blue, and numbered 5, 6, and 7. ; ; Moncrief notes three main segments of the program: ; ; 1.) Handle the communication of the PIC with the PC. ; 2.) Handle the internal logic of the keyboard itself (ie how it ; deals with CTRL, ALT, etc). ; 3.) Handle logic with switches. ; ; these should all work nicely together (obviously). The PIC/PC and ; switch parts should have nice, easy interfaces to the logic part, ; like CALL get_chord; should return a with a seven-bit number in ; the W register, so that the logic can deal with it appropriately. ; ; Similarly, there should really be only a couple of functions of ; the PC/PIC part; things like send, receive, and so on. Things are ; made considerably more complicated by the fact that the keyboard ; spec calls for two-way IO between the board and the keys. It's not ; necessarily just a matter of shoving bytes down the line. ; ; There is no `macros mode' in this keyer implementation, since ; there is no non-volatile memory (such as EPROM) which the user has ; access to. ; LIST p=16C63 #include "P16C63.INC" __config _HS_OSC | _WDT_ON | _PWRTE_OFF | _CP_OFF | _BODEN_OFF ;; assumes osc HS, 8MHz ;; assumes WDT on ;; assumes PUT off ;; assumes BOD off ;; assumes CP off #define REVISION 0x1C, 0x16 ;; constants #define ACK 0xFA #define NAK 0xFE #define DONTCARE 0xFF #define BEGIN_E0 0x80 #define EXTENDED 0xFE #define FUNCTION_EX 0xFD ;; macros ; clock 1 == pin 5, data 1 == pin 1 ; clock 2 == pin 6, data 2 == pin 2 #define K1C PORTB, 3; keyboard clock #define K1D PORTB, 2; keyboard data #define KBD_ENABLED KBDSTATUS, 0 #define KBD_RESET KBDSTATUS, 1 #define KBD_ABORT KBDSTATUS, 2 #define KBD_DISPATCH KBDSTATUS, 3 #define KBD_TIMER KBDSTATUS, 4 #define KBD_CTRL KBDSTATUS, 5 #define KBD_ALT KBDSTATUS, 6 #define KBD_SHIFT KBDSTATUS, 7 #define KBD_WANTTYPEMATIC KBDSTATUS2, 0 #define KBD_MAGIC KBDSTATUS2, 1 #define KBD_CTRL2 KBDSTATUS2, 5 #define KBD_ALT2 KBDSTATUS2, 6 #define KBD_SHIFT2 KBDSTATUS2, 7 ;; registers #define TMP1 0x20 #define TMP2 0x21 #define SCRATCH 0x22 #define SCRATCHMASK 0x23 #define STROBE_COUNTER 0x24 #define BITCOUNT 0x25 #define KEYVAL 0x26 #define PREVKEYVAL 0x27 #define ACTFLAG 0x28 #define HEAD 0x29 ; keyboard fifo #define TAIL 0x2A ; for keyboard fifo #define SENDNOW 0x2B #define SENDSPOT 0x2C #define READNOW 0x2D #define READSPOT 0x2E #define PUSHVAL 0x2F #define KBDSTATUS 0x30 #define KBDSTATUS2 0x31 #define ACTKEYVAL 0x32 #define CODEPAGETMP 0x35 #define COUNTERTIMER 0x36 #define TYPEMATIC 0x37 #define TYPEMATIC_MODE 0x38 #define FUNCTION_HI 0x3B #define FUNCTION_LO 0x3C #define BUFSTART 0x40 #define BUFEND 0x5F #define LEDMODE 0x64 #define LEDCOUNT 0x68 #define MODE 0x6A #define PREVMODE 0x6C #define KBD_1SHOT 0x6E,1 #define KEYDOWN 0x6E, 2 ;=======macro to release one of the keyboard ps2 lines ; otherwise held high by weak pullups release: macro port, bit BSF STATUS, RP0 BSF port, bit BCF STATUS, RP0 endm ;macro to drive the ps2 keyboard pins line low drivelow: macro port, bit BCF port, bit BSF STATUS, RP0 BCF port, bit BCF STATUS, RP0 endm #define if_set BTFSC #define if_clear BTFSS ; macros for keyboard fifo clear_fifo: macro head, strt MOVLW strt MOVWF head MOVWF head+1 endm push_fifo: macro head, var MOVF head+1, W MOVWF FSR MOVF var, W MOVWF INDF INCF head+1, F endm pushw_fifo: macro head MOVWF PUSHVAL MOVF head+1, W MOVWF FSR MOVF PUSHVAL, W MOVWF INDF INCF head+1, F endm pushlit_fifo: macro head, lit MOVF head+1, W MOVWF FSR MOVLW lit MOVWF INDF INCF head+1, F endm pop_fifo: macro head MOVF head, W MOVWF FSR MOVF INDF, W MOVWF PUSHVAL INCF head, F endm unpop_fifo: macro head MOVWF PUSHVAL DECF head, F MOVF head, W MOVWF FSR MOVF PUSHVAL, W MOVWF INDF endm check_fifo: macro head MOVF head, W SUBWF head+1, W endm ; read a single bit off the keyboard ps2 lines readbit: macro clockport, clockbit, dataport, databit drivelow clockport, clockbit CALL wait_phase CALL wait_phase CLRF READSPOT if_set dataport, databit BSF READSPOT, 0 release clockport, clockbit CALL wait_phase CALL wait_phase endm ; write a single bit to the keyboard ps2 lines writebit: macro clockport, clockbit, dataport, databit local wb1, wb2 if_clear SENDSPOT, 0 GOTO wb1 release dataport, databit GOTO wb2 wb1: drivelow dataport, databit wb2: drivelow clockport, clockbit CALL wait_phase CALL wait_phase release clockport, clockbit CALL wait_phase CALL wait_phase endm ; what does this do? toggle: macro var, bit, press, release local l1, l2 if_set var, bit GOTO l1 if_set var+1, bit GOTO l2 BSF var, bit CALL press RETURN l1: BCF var, bit BSF var+1, bit CALL press RETURN l2: BCF var+1, bit CALL release RETURN endm ; fixes up a return from a long jump; fixes up the program counter high ; if you jump beyond 512 byte boundaries, problem with the program counter? fixcodepage: macro local currentpc MOVWF CODEPAGETMP currentpc: MOVLW high currentpc MOVWF PCLATH MOVF CODEPAGETMP, W endm ; compare register with value and jump to label if equal cmp_branch: macro reg, val, lab MOVF reg, W SUBLW val if_set STATUS, Z GOTO lab endm ; macro to store low and high values of program counter for specific mem loc table_addr: macro val, addr RETLW val RETLW high addr RETLW low addr endm led_on: macro led_bit BSF PORTC, led_bit endm led_off: macro led_bit BCF PORTC, led_bit endm toggle_led: macro led_bit local l_off local l_on local done if_set PORTC, led_bit goto l_off goto l_on l_off: led_off led_bit goto done l_on: led_on led_bit done: endm ; makes sure table doesn't span 256 boundary ; will complain during compile; if problem put some NOPs in front of it ; or put an org to move to certain spot ensure_table: macro start, end if ((high start) - (high end)) !=0 ERROR start endif endm ; start of program memory ORG 0 GOTO begin ; calls initialization for processor begin: CALL init_wdt; initialize watchdog timer CALL init_a ; initialize port A CALL init_b ; initialize port B CALL init_c ; initialize port C CALL init_keypad ; initialize keypad CALL init_keyboard ; initialize keyboard CALL init_timer1 ; initialize timer1 CALL post ; power on self-test mainloop: CLRWDT CALL poll_timer if_set KBD_RESET CALL post if_set KBD_RESET CALL init_keyboard if_set KBD_ENABLED CALL do_keypad CALL do_port1 CALL led_blink release K1C ; just to be sure release K1D ;if_set KBD_SHIFT ;led_on 4 ;if_clear KBD_SHIFT ;led_off 4 ; if_set KEYDOWN ;led_on 5 ;if_clear KEYDOWN ;led_off 5 ;if_set KBD_ALT ;led_on 6 ;if_clear KBD_ALT ;led_off 6 GOTO mainloop exp2: fixcodepage ADDWF PCL,F exp2_table: RETLW D'1' RETLW D'2' RETLW D'4' RETLW D'8' RETLW D'16' RETLW D'32' RETLW D'64' RETLW D'128' do_port1: if_clear K1C ; 8042 will hold clock low to indicate busy RETURN if_set K1D ; data low ==> 8042 will send, we recv GOTO port1_send port1_recv: CALL read_word_1 BSF KBD_DISPATCH CALL dispatch_command1 BCF KBD_DISPATCH RETURN port1_send: ; check to see if we want to send check_fifo HEAD if_set STATUS, Z GOTO port1_send_no port1_send_yes: ; yes we do pop_fifo HEAD ; get it out of the fifo1 MOVWF SENDNOW CALL write_word_1 CALL check_abort1 RETURN port1_send_no: clear_fifo HEAD, BUFSTART RETURN ; reads a word of the ps2 device (port1); calls readbit1 read_word_1: CLRF READNOW CALL read_bit_1 if_set READSPOT, 0 BSF READNOW, 0 CALL read_bit_1 if_set READSPOT, 0 BSF READNOW, 1 CALL read_bit_1 if_set READSPOT, 0 BSF READNOW, 2 CALL read_bit_1 if_set READSPOT, 0 BSF READNOW, 3 CALL read_bit_1 if_set READSPOT, 0 BSF READNOW, 4 CALL read_bit_1 if_set READSPOT, 0 BSF READNOW, 5 CALL read_bit_1 if_set READSPOT, 0 BSF READNOW, 6 CALL read_bit_1 if_set READSPOT, 0 BSF READNOW, 7 CALL read_bit_1 ; parity bit, ignore it CALL read_bit_1 ; stop bit, ignore it ; here comes the ACK BCF SENDSPOT, 0 CALL write_bit_1 read_1_ack: if_clear K1C GOTO read_1_ack ; TODO this is new, please check!!! release K1D RETURN read_bit_1: readbit K1C, K1D RETURN write_word_1: if_clear K1C GOTO abort_mid_write drivelow K1D CALL wait_phase if_clear K1C GOTO abort_mid_write CLRF SENDSPOT CALL write_bit_1 if_clear K1C GOTO abort_mid_write CLRF SENDSPOT if_set SENDNOW, 0 BSF SENDSPOT, 0 CALL write_bit_1 if_clear K1C GOTO abort_mid_write CLRF SENDSPOT if_set SENDNOW, 1 BSF SENDSPOT, 0 CALL write_bit_1 if_clear K1C GOTO abort_mid_write CLRF SENDSPOT if_set SENDNOW, 2 BSF SENDSPOT, 0 CALL write_bit_1 if_clear K1C GOTO abort_mid_write CLRF SENDSPOT if_set SENDNOW, 3 BSF SENDSPOT, 0 CALL write_bit_1 if_clear K1C GOTO abort_mid_write CLRF SENDSPOT if_set SENDNOW, 4 BSF SENDSPOT, 0 CALL write_bit_1 if_clear K1C GOTO abort_mid_write CLRF SENDSPOT if_set SENDNOW, 5 BSF SENDSPOT, 0 CALL write_bit_1 if_clear K1C GOTO abort_mid_write CLRF SENDSPOT if_set SENDNOW, 6 BSF SENDSPOT, 0 CALL write_bit_1 if_clear K1C GOTO abort_mid_write CLRF SENDSPOT if_set SENDNOW, 7 BSF SENDSPOT, 0 CALL write_bit_1 if_clear K1C GOTO abort_mid_write MOVF SENDNOW, W CALL bitcount XORLW 0x01 MOVWF SENDSPOT CALL write_bit_1 ;if_clear K1C ;GOTO abort_mid_write BSF SENDSPOT, 0 CALL write_bit_1 ;if_clear K1C ;GOTO abort_mid_write BSF SENDSPOT, 0 CALL write_bit_1 ;BCF KBD_ABORT ; protocol handshake (comes at end of sending a byte?) write_1_handshake: if_set K1C ;GOTO write_1_handshake release K1D RETURN write_bit_1: writebit K1C, K1D RETURN ; if while you're sending a byte the host pulls clock? line or data? line ; abort current byte ; host can say can't take it... abort_mid_write: BSF KBD_ABORT RETURN check_abort1: if_clear KBD_ABORT RETURN BCF KBD_ABORT ; oh hell if_set KBD_DISPATCH GOTO check_abort_dispatch1 MOVF SENDNOW, W unpop_fifo HEAD release K1C release K1D RETURN check_abort_dispatch1: ; oh hell hell hell! release K1C release K1D CALL wait_for_send1 CALL write_word_1 RETURN init_keypad: MOVLW 0x01 MOVWF STROBE_COUNTER CLRF KEYVAL CLRF PREVKEYVAL CLRF ACTFLAG CLRF LEDMODE RETURN init_keyboard: MOVLW 0x7F MOVWF TYPEMATIC clear_fifo HEAD, BUFSTART ;pushlit_fifo HEAD, 0xAA BSF KBD_ENABLED BCF KBD_RESET BCF KBD_ABORT BCF KBD_DISPATCH BCF KBD_CTRL BCF KBD_ALT BCF KBD_SHIFT BCF KBD_1SHOT CLRF MODE CLRF PREVMODE CLRF KBDSTATUS2 RETURN ; give the watchdog a large time out init_wdt: CALL wdt_check BSF STATUS, RP0 BSF OPTION_REG, PSA BSF OPTION_REG, PS2 BSF OPTION_REG, PS1 BSF OPTION_REG, PS0 BCF STATUS, RP0 RETURN wdt_check: if_clear STATUS, NOT_POR RETURN if_clear STATUS, NOT_BOR RETURN if_set STATUS, NOT_TO RETURN if_clear STATUS, NOT_PD RETURN GOTO err ; port A initialization ; set up A0:A5 as "outputs" to read the switches init_a: BCF STATUS, RP0 MOVLW 0x00 MOVWF PORTA BSF STATUS, RP0 MOVLW 0xFF MOVWF TRISA BCF STATUS, RP0 RETURN ; set up port B7:B0 as inputs ; enable the internal pull-ups ; enable interrupt-on-change for B7:B4 ; pin 28 (RB7 is the input of switch common (ground)) ; RB3 and RB2 are keyboard inputs (they start off as inputs but ; get toggled while running) init_b: BSF STATUS, RP0 MOVLW 0xFF MOVWF TRISB BCF OPTION_REG, NOT_RBPU BCF STATUS, RP0 CLRF PORTB RETURN ; set up port C4, C5, and C6 as outputs ; set up port C0, C1, C2, C3, and C7 as inputs ; decided to use C7 rather than C4 as an input ; (top LED removed to be used as input) init_c: BCF STATUS, RP0 CLRF PORTC BSF STATUS, RP0 MOVLW 0x8F ; WOZ changed from 0F to 8F to make bit 7 an input MOVWF TRISC BCF STATUS, RP0 RETURN ; controls key scanrate init_timer1: BCF T1CON, TMR1CS BCF T1CON, T1OSCEN BCF T1CON, T1CKPS1 BCF T1CON, T1CKPS0 BSF T1CON, TMR1ON CALL reset_timer RETURN reset_timer: CLRF TMR1L CLRF TMR1H CLRF COUNTERTIMER CLRF TYPEMATIC_MODE BCF KBD_TIMER RETURN poll_timer: if_set KBD_TIMER GOTO poll_timer_set poll_timer_clear: if_clear TMR1H, 7 RETURN INCF COUNTERTIMER, F BSF KBD_TIMER RETURN poll_timer_set: if_set TMR1H, 7 RETURN INCF COUNTERTIMER, F BCF KBD_TIMER RETURN ; talks to ps2 keyboard port; checks to see if data nees to be sent ; or if any data's coming in ; checks to see if we need to do autorepeat ; typematic is ps2 autorepeat ; the ps2 host tells the keyboard what the autorepeat rate is ; it's a nonlinear 5bit setting in the spec ; but here for simplicity it's linear rate ; both delay and rate can be set by the host check_typematic: ; same keyval as last run... check for possible typematic action MOVF KEYVAL, W ADDLW 0 if_set STATUS, Z RETURN MOVF TYPEMATIC, W XORLW 0x7F if_set STATUS, Z RETURN MOVF TYPEMATIC_MODE, W ADDLW 0 if_set STATUS, Z GOTO check_typematic_0 ; short and rapid MOVF TYPEMATIC, W ANDLW 0x1F ADDLW 0x02 SUBWF COUNTERTIMER, W if_clear STATUS, C RETURN GOTO check_typematic_fini check_typematic_0: ; long initial MOVLW D'15' if_set TYPEMATIC, 5 ADDLW D'15' if_set TYPEMATIC, 6 ADDLW D'15' SUBWF COUNTERTIMER, W if_clear STATUS, C RETURN check_typematic_fini: CALL reset_timer MOVLW 0x01 MOVWF TYPEMATIC_MODE MOVF KEYVAL, W MOVWF ACTKEYVAL GOTO actonkey ; compares current keys held down to prev. set held down; ; decides if need to take action ; read the current status actonkey: ; debug -- mirror keyval in the LEDs ; SWAPF KEYVAL, W ; ANDLW 0x70 ; MOVWF PORTC MOVF PREVKEYVAL, W CALL bitcount ADDLW 0x00 if_set STATUS, Z BCF KEYDOWN MOVF KEYVAL, W SUBWF PREVKEYVAL, W if_clear STATUS, Z GOTO actonkey_differs actonkey_same: if_set KBD_WANTTYPEMATIC GOTO check_typematic RETURN actonkey_differs: BSF KBD_WANTTYPEMATIC CALL reset_timer MOVF KEYVAL, W CALL bitcount MOVWF TMP1 MOVF PREVKEYVAL, W CALL bitcount MOVWF TMP2 MOVF PREVKEYVAL, W MOVWF ACTKEYVAL MOVF KEYVAL, W MOVWF PREVKEYVAL MOVF TMP2, W SUBWF TMP1, W if_clear STATUS, C GOTO actonkey_neg actonkey_pos: CLRF ACTFLAG ;MOVLW 0x40 ;MOVWF PORTC RETURN actonkey_neg: if_clear ACTFLAG, 1 GOTO actonkey_act ;MOVLW 0x20 ;MOVWF PORTC RETURN readkeyval: ; make bloody sure RB7 (pin 28) has stableized... ; loop until RB7 is stable (same valued) for wait_medium ; wait_medium is (256 ticks of the instruction cycle clock) debounce: MOVF PORTB, W ANDLW 0x80 MOVWF TMP1 CALL wait_medium MOVF PORTB, W ANDLW 0x80 XORWF TMP1, W if_clear STATUS, Z GOTO debounce ; ok, we're debounced ; TMP1, bit 7 is now the thing to look at. ; if it's logic 0, the key has been depressed ; if it's logic 1, the key is not depressed ; STROBE_COUNTER tells us which key we're talking about ; this is easy now; just load W with the value of strobe_counter MOVF STROBE_COUNTER, W; load accumulator with contensts of strobe_c ounter CALL exp2 ; set W to contain one bit high MOVWF SCRATCH ; store accumulator in SCRATCH for later ; clear the bit in KEYVAL XORLW 0xFF ; flip all bits in W over ANDWF KEYVAL, F ; and W with value in KEYVAL ; F is binary quantity, tells "file" (RAM) or accumulator (W) ; if TMP1, bit 7 is logic 1, the key is not pressed ; and we just return if_set TMP1, 7 ; if the key is not pressed ; TMP1 responsive to pin28 ; TMP1 is all of portC; pin28 is 7th bit of C RETURN ; otherwise, we set the bit, then return MOVF SCRATCH, W ; move SCRATCH into W (LDA SCRATCH) ADDWF KEYVAL, F ; add back into KEYVAL RETURN ; turn off oldport/oldbit and turn on newport/newbit ; make oldport/oldbit an input ; make newport/newbit an output logic 0 twiddle_pins: macro oldport, oldbit, newport, newbit BSF STATUS, RP0 ;bit set file (set=bank1) ;sets a bit in a file register ;bit 5 of location 03h is RP0 ;PIC16C63.inc is the include file ;defines STATUS=3; RP0=5 BSF oldport, oldbit BCF STATUS, RP0 ;bank bit clear file (clear=bank0) BCF newport, newbit BSF STATUS, RP0 BCF newport, newbit BCF STATUS, RP0 endm ; outer loop: calls readkeyval and actonkey to decide whether to do something do_keypad: CALL readkeyval CALL actonkey INCF STROBE_COUNTER, F MOVF STROBE_COUNTER, W fixcodepage ADDWF PCL, F do_keypad_table: GOTO strobe_0 GOTO strobe_1 GOTO strobe_2 GOTO strobe_3 GOTO strobe_4 GOTO strobe_5 GOTO strobe_6 GOTO strobe_7 GOTO strobe_8 do_keypad_table_end: ensure_table do_keypad_table, do_keypad_table_end strobe_0: twiddle_pins PORTC, 3, PORTA, 0 RETURN strobe_1: twiddle_pins PORTA, 0, PORTA, 1 RETURN strobe_2: twiddle_pins PORTA, 1, PORTA, 2 RETURN strobe_3: twiddle_pins PORTA, 2, PORTA, 3 RETURN strobe_4: twiddle_pins PORTA, 3, PORTA, 4 RETURN strobe_5: twiddle_pins PORTA, 4, PORTA, 5 RETURN strobe_6: twiddle_pins PORTA, 5, PORTB, 4 RETURN strobe_7: twiddle_pins PORTB, 4, PORTC, 3 RETURN strobe_8: CLRF STROBE_COUNTER GOTO strobe_0 bitcount: MOVWF BITCOUNT CLRW if_set BITCOUNT, 0 ADDLW 0x01 if_set BITCOUNT, 1 ADDLW 0x01 if_set BITCOUNT, 2 ADDLW 0x01 if_set BITCOUNT, 3 ADDLW 0x01 if_set BITCOUNT, 4 ADDLW 0x01 if_set BITCOUNT, 5 ADDLW 0x01 if_set BITCOUNT, 6 ADDLW 0x01 if_set BITCOUNT, 7 ADDLW 0x01 RETURN wait_medium: MOVLW 0xFF GOTO wait_phase_sub wait_phase: MOVLW 0x07 wait_phase_sub: ADDLW 0xFF if_clear STATUS, Z GOTO wait_phase_sub RETURN dispatch_ack: pushlit_fifo HEAD, ACK RETURN dispatch_nak pushlit_fifo HEAD, NAK RETURN dispatch_ee: pushlit_fifo HEAD, 0xEE RETURN wait_for_recv: release K1C ; just to be sure release K1D if_clear PORTB, 4 ; in the emulator??? RETURN ; skip this crap if_clear K1C GOTO wait_for_recv if_set K1D ; data low ==> 8042 will send, we recv GOTO wait_for_recv RETURN wait_for_send1: release K1C ; just to be sure release K1D if_clear K1C GOTO wait_for_send1 if_clear K1D ; data low ==> 8042 will send, we recv GOTO wait_for_send1 RETURN dispatch_f5: clear_fifo HEAD, BUFSTART BCF KBD_ENABLED pushlit_fifo HEAD, ACK RETURN dispatch_f4: clear_fifo HEAD, BUFSTART BSF KBD_ENABLED pushlit_fifo HEAD, ACK RETURN dispatch_f2: BSF KBD_ENABLED pushlit_fifo HEAD, ACK pushlit_fifo HEAD, 0xAB pushlit_fifo HEAD, 0x83 RETURN dispatch_f0: CALL wait_for_send1 MOVLW ACK MOVWF SENDNOW CALL write_word_1 CALL check_abort1 CALL wait_for_recv CALL read_word_1 MOVF READNOW, W if_clear STATUS, Z RETURN pushlit_fifo HEAD, ACK pushlit_fifo HEAD, 0x02 RETURN ; dispatechs the 0xED command from the host ; to set the LEDs dispatch_ed: CALL wait_for_send1 MOVLW ACK MOVWF SENDNOW CALL write_word_1 CALL check_abort1 CALL wait_for_recv CALL read_word_1 MOVF READNOW, W SWAPF READNOW, W MOVWF PORTC CALL wait_for_send1 MOVLW ACK MOVWF SENDNOW CALL write_word_1 CALL check_abort1 RETURN dispatch_f3: CALL wait_for_send1 MOVLW ACK MOVWF SENDNOW CALL write_word_1 CALL check_abort1 CALL wait_for_recv CALL read_word_1 MOVF READNOW, W MOVWF TYPEMATIC CALL wait_for_send1 MOVLW ACK MOVWF SENDNOW CALL write_word_1 CALL check_abort1 RETURN ;; Now I have to start thinking for myself. Adam, at this point, ;; starts `check typematic'. I want a different set of functionality ;; than he does; Steve has different plans for this keyboard. So ;; I'm going to try to lift out the `which chord' code out, and isolate ;; it. dispatch_unknown: ; my god man! pushlit_fifo HEAD, ACK RETURN longwait: if_clear PORTB, 4 RETURN MOVLW 0xFF MOVWF TMP2 lw_0 MOVLW 0xFF lw_1: ADDLW 0xFF if_clear STATUS, Z GOTO lw_1 MOVF TMP2, W ADDLW 0xFF MOVWF TMP2 if_set STATUS, Z RETURN MOVWF TMP2 GOTO lw_0 debug_out: MOVF READNOW, W MOVWF TMP1 MOVWF PORTC CALL longwait CALL longwait CALL longwait SWAPF TMP1, W MOVWF PORTC CALL longwait CALL longwait CALL longwait RETURN dispatch_fe: MOVF SENDNOW, W unpop_fifo HEAD RETURN ; adds number to program counter (computed jump) ; jump table ; table for commands from host dispatch_command1: MOVLW high dispatch_table MOVWF PCLATH MOVLW 0xED SUBWF READNOW, W if_clear STATUS, C GOTO dispatch_unknown ; unknown value! ADDWF PCL, F dispatch_table: GOTO dispatch_ed ; 0xED GOTO dispatch_ee ; 0xEE GOTO dispatch_nak ; 0xEF // DONE GOTO dispatch_f0 ; 0xFO GOTO dispatch_nak ; 0xF1 // DONE GOTO dispatch_f2 ; 0xF2 GOTO dispatch_f3 ; 0xF3 GOTO dispatch_f4 ; 0xF4 GOTO dispatch_f5 ; 0xF5 GOTO dispatch_ack ; 0xF6 // DONE GOTO dispatch_ack ; 0xF7 // DONE GOTO dispatch_ack ; 0xF8 // DONE GOTO dispatch_ack ; 0xF9 // DONE GOTO dispatch_ack ; 0xFA // DONE GOTO dispatch_ack ; 0xFB // TODO GOTO dispatch_ack ; 0xFC // TODO GOTO dispatch_ack ; 0xFD // TODO GOTO dispatch_fe ; 0xFE GOTO reset ; 0xFF // stack overflows are ignored dispatch_table_end: ensure_table dispatch_table, dispatch_table_end RETURN reset: CALL wait_for_send1 MOVLW ACK MOVWF SENDNOW CALL write_word_1 CALL check_abort1 CALL wait_for_send1 MOVLW 0xAA MOVWF SENDNOW CALL write_word_1 CALL check_abort1 BSF KBD_RESET RETURN post: MOVLW 0xF0 MOVWF PORTC CALL longwait MOVLW 0x00 MOVWF PORTC RETURN err: CALL longwait MOVLW 0xA0 MOVWF PORTC CALL longwait MOVLW 0x50 MOVWF PORTC GOTO err actonkey_act: if_set KEYDOWN RETURN bsf KEYDOWN MOVF ACTKEYVAL, W ;; We have four modes to deal with, plus the metakeys. ;; My assembler is anything but clean, but I'm going to attempt to do ;; a somewhat legible job. ;; Currently, we have a chord-code in the working register. MOVWF SCRATCH ; Save the keypress somewhere... SUBLW b'0011011' ; Check if it's CTRL... if_set STATUS, Z ; it WAS control! GOTO actonkey_ctrl ; MOVF SCRATCH,W ; SUBLW b'0010111' ; subtract the code for ALT if_set STATUS, Z GOTO actonkey_alt ; It was ALT! MOVF SCRATCH,W SUBLW b'1000000' if_set STATUS, Z ; Was it Shift? GOTO actonkey_shift ; It was shift MOVF SCRATCH,W ;; Now we look for 1-shot modes: SUBLW b'0010000' ; Was it the 1-shot numbers/symbols mode? if_set STATUS, Z ; It was! GOTO act1_numbers ;; MOVF SCRATCH,W SUBLW b'0010001' ; Was it the 1-shot functions mode? if_set STATUS,Z ; It was GOTO act1_functions ; hit the functions mode ;; Now we want to translate the character (which we know by now ;; is not a metakey) into a scancode, which we decide based on the ;; current mode. MOVF SCRATCH,W ; get the keyval back; SUBLW b'0011010' ; was the key to enter the keypad mode? if_set STATUS,Z ; GOTO setmode_keypad ; another random function to set the mode ; MOVF SCRATCH,W ; get the keyval back; ; SUBLW b'1001111' ; was it the Caps lock mode? ; if_set STATUS, Z ; it was ; GOTO setmode_capslock MOVF SCRATCH,W ; get the keyval back SUBLW b'0011111' ; was it the locking numbers/symbols? if_set STATUS,Z ; yep! GOTO setmode_numbers ; MOVF SCRATCH, W ; Finally, check if it was the panic button: SUBLW d'112' ; Was it the panic button? if_set STATUS, Z ; it was CALL unsetmode_abs ; an absolute reset ;; Define a few modes: We're going to use the MODE register ;; 'cause I already got it. Let ;; MODE = d'31' is going to be the Numbers/symbols check_numbers: MOVF MODE,W ; Let's look at the current mode... SUBLW d'31' ; is it the Locking Numbers/symbols mode? if_clear STATUS, Z GOTO check_keypad ; nope. GOTO the next one, then. CALL actonkey_numbers MOVF TMP1, W MOVWF SCRATCH ; save the key; SUBLW DONTCARE ; check if we care if_set STATUS, Z ; RETURN ; go somewhere else MOVF SCRATCH, W ; restore GOTO complete ; finish the 1-shot keypresses... check_keypad: MOVF MODE,W SUBLW d'26' ; is the Keypad mode? if_clear STATUS, Z ; It is not; go to the letters mode GOTO check_functions CALL actonkey_keypad GOTO complete ; now for the letters mode... check_functions: MOVF MODE,W SUBLW d'17' if_clear STATUS, Z GOTO check_letters CALL actonkey_function GOTO complete check_letters: CALL actonkey_letters GOTO complete ;; NOTE TO SELF: We need to deal with 1-shot vs. persistant modes ;; If the mode is entered into with a 1-shot chord, set a bit called ;; KBD_1SHOT. Then, at the in the complete function, we have ;; do it again... complete: if_set KBD_1SHOT ; check if we've been in a 1-shot mode call clear_1shot ; toggle_led 6 call undo_ctrlaltshift ; release the metakeys RETURN actonkey_ctrl: call press_ctrl ; Press control BSF KBD_CTRL ; set the Control bit high. ; CALL wait_medium ; CALL wait_medium RETURN actonkey_alt: CALL press_alt ; press ALT. BSF KBD_ALT ; set the ALT bit high. ; CALL longwait RETURN actonkey_shift: call press_shift ; press SHIFT BSF KBD_SHIFT ; set the SHIFT bit high RETURN act1_numbers: BSF KEYDOWN BSF KBD_1SHOT ; set the 1-shot bit MOVF MODE,W SUBLW d'31' if_set STATUS,Z GOTO check_numbers; We're already in numbers mode, but for some ;; twisted reason, the BAT designers decided to have this particular ;; keycombination send if it was already in numbers mode. ;; So I just put this chord in the numbers table as , and ;; it should magically send a space under circumstances of a double- ;; press. Not that I approve of this practice; it's an evil hack. ;; However, assembler lends itself to evil hacks, and no one ;; has mentioned to me any good programming techniques under assembley ;; language... MOVF MODE,W SUBLW d'26' if_set STATUS,Z GOTO check_numbers ; Like before, if we're in keypad mode, send ;; a ... ;; MOVF MODE,W MOVWF PREVMODE ; copy mode to PREVMODE MOVLW d'31' ; load acumulator with literal d'31' MOVWF MODE ; put d'31' in mode RETURN ; we're done act1_functions: bsf KEYDOWN BSF KBD_1SHOT ; set the 1-shot bit MOVF MODE,W SUBLW d'17' if_set STATUS,Z RETURN ; We're already in functions mode MOVF MODE,W MOVWF PREVMODE ; copy mode to PREVMODE MOVLW d'17' ; load acumulator with literal d'17' MOVWF MODE ; put d'17' in mode RETURN ; we're done actonkey_letters: BSF ACTFLAG, 1 MOVF ACTKEYVAL, W ; get the keyvalue to lookup CALL lookup_letters MOVWF TMP1 CALL key_to_scan RETURN actonkey_keypad: BSF ACTFLAG, 1 MOVF ACTKEYVAL, W ; get the keyvalue to lookup CALL lookup_keypad MOVWF TMP1 CALL key_to_scan RETURN actonkey_function: BSF ACTFLAG, 1 MOVF ACTKEYVAL, W ; get the keyvalue to lookup CALL lookup_function MOVWF TMP1 CALL key_to_scan RETURN actonkey_numbers: BSF ACTFLAG, 1 MOVF ACTKEYVAL, W ; get the keyvalue to lookup CALL lookup_numbers MOVWF TMP1 CALL key_to_scan fixcodepage RETURN lookup_letters: CALL lookup_letters_sub fixcodepage RETURN ; converts keycodes scan codes ; this does not change with changes in chording layout, etc. lookup_letters_sub: MOVWF TMP1 MOVLW high UUU MOVWF PCLATH MOVF TMP1, W MOVWF PCL lookup_function: CALL lookup_function_sub fixcodepage RETURN ; converts keycodes scan codes ; this does not change with changes in chording layout, etc. lookup_function_sub: MOVWF TMP1 MOVLW high function_chord2key MOVWF PCLATH MOVF TMP1, W MOVWF PCL lookup_keypad: CALL lookup_keypad_sub fixcodepage RETURN ; converts keycodes scan codes ; this does not change with changes in chording layout, etc. lookup_keypad_sub: MOVWF TMP1 MOVLW high keypad_chord2key MOVWF PCLATH MOVF TMP1, W MOVWF PCL lookup_numbers: CALL lookup_numbers_sub fixcodepage RETURN ; converts keycodes scan codes ; this does not change with changes in chording layout, etc. lookup_numbers_sub: MOVWF TMP1 MOVLW high numbers_chord2key MOVWF PCLATH MOVF TMP1, W MOVWF PCL setmode_keypad: bsf KEYDOWN MOVF MODE,W ; get the current mode; SUBLW d'26' if_set STATUS, Z ; we're already in the keypad mode goto unsetmode MOVF MODE,W ; get the current mode again MOVWF PREVMODE ; save it to previous mode MOVLW d'26' ; put d'26' in acumulator MOVWF MODE ; set it equal to mode; RETURN setmode_numbers: bsf KEYDOWN MOVF MODE,W ; get the current mode; SUBLW d'31' if_set STATUS, Z ; we're already in the numbers mode goto unsetmode MOVF MODE,W ; get the current mode again MOVWF PREVMODE ; save it to previous mode MOVLW d'31' ; put d'31' in acumulator MOVWF MODE ; set it equal to mode; RETURN ;setmode_capslock: ; MOVF MODE,W ; get the current mode; ; SUBLW d'79' ; if_set STATUS, Z ; we're already in the capslock mode ; goto unsetmode_capslock ; MOVF MODE,W ; get the current mode again ; MOVWF PREVMODE ; save it to previous mode ; MOVLW d'79' ; put d'79' in acumulator ; MOVWF MODE ; set it equal to mode; ; CALL press_shift ; RETURN ; we're done. unsetmode: MOVF PREVMODE, W ; put previous mode in acumulator MOVWF MODE ; restore previous mode RETURN ;unsetmode_capslock: ; MOVF PREVMODE, W ; put previous mode in acumulator ; MOVWF MODE ; restore previous mode ; CALL release_shift ; release shift ; RETURN unsetmode_abs: CLRF PREVMODE CLRF MODE CALL undo_ctrlaltshift BCF KBD_1SHOT RETURN key_to_scan_sub: MOVWF TMP1 MOVLW high key2scan MOVWF PCLATH MOVF TMP1, W MOVWF PCL key_to_scan: MOVWF TMP2 CALL key_to_scan_sub fixcodepage MOVWF TMP1 SUBLW EXTENDED if_set STATUS, Z GOTO key_to_scan_extended MOVF TMP1, W ; SUBLW FUNCTION_EX ; if_set STATUS, Z ; GOTO key_to_scan_function if_set TMP1, 7 GOTO key_to_scan_e0 ; no modifiers, just do it! BSF KEYDOWN ;we're sending it for sure push_fifo HEAD, TMP1 pushlit_fifo HEAD, 0xF0 push_fifo HEAD, TMP1 ;CALL undo_ctrlaltshift RETURN key_to_scan_e0 BCF TMP1, 7 ; add 0xE0 before sending pushlit_fifo HEAD, 0xE0 push_fifo HEAD, TMP1 pushlit_fifo HEAD, 0xE0 pushlit_fifo HEAD, 0xF0 push_fifo HEAD, TMP1 ;CALL undo_ctrlaltshift RETURN extended_jmp: MOVLW high extended_data MOVWF PCLATH MOVF TMP2, W MOVWF PCL key_to_scan_extended: CALL key_to_scan_extended_helper ;CALL undo_ctrlaltshift RETURN key_to_scan_extended_helper: MOVF TMP2, W MOVWF TMP1 MOVLW 0x00 ;low extended_data MOVWF TMP2 extended_again: CALL extended_jmp fixcodepage ADDLW 0 if_set STATUS, Z RETURN SUBWF TMP1, W if_set STATUS, Z GOTO extended_gotone extended_notme: INCF TMP2, F CALL extended_jmp fixcodepage ADDLW 0 if_clear STATUS, Z GOTO extended_notme INCF TMP2, F GOTO extended_again extended_gotone: INCF TMP2, F CALL extended_jmp fixcodepage ADDLW 0 if_set STATUS, Z RETURN pushw_fifo HEAD GOTO extended_gotone ;function_jmp: ; MOVLW high function_data ; MOVWF PCLATH ; MOVF TMP2, W ; MOVWF PCL ;key_to_scan_function: ; BCF KBD_WANTTYPEMATIC ; MOVF TMP2, W ; MOVWF TMP1 ; MOVLW low function_data ; MOVWF TMP2 ;function_again: ; CALL function_jmp ; fixcodepage ; ADDLW 0 ; if_set STATUS, Z ; RETURN ; SUBWF TMP1, W ; if_set STATUS, Z ; GOTO function_gotone ;function_notme: ; INCF TMP2, F ; INCF TMP2, F ; INCF TMP2, F ; GOTO function_again ; some keys don't send scancodes but call functions inside the pic instead ; like the shift key, need to call a function ; sparse (walkthrough) table ;function_gotone: ; INCF TMP2, F ; CALL function_jmp ; fixcodepage ; MOVWF FUNCTION_HI ; INCF TMP2, F ; CALL function_jmp ; fixcodepage ; MOVWF FUNCTION_LO ; CALL function_flee ; fixcodepage ; RETURN ;function_flee: ; MOVF FUNCTION_HI, W ; MOVWF PCLATH ; MOVF FUNCTION_LO, W ; MOVWF PCL press_ctrl: BSF KEYDOWN pushlit_fifo HEAD, 0x14 RETURN press_alt: BSF KEYDOWN pushlit_fifo HEAD, 0x11 RETURN press_shift: BSF KEYDOWN pushlit_fifo HEAD, 0x12 RETURN release_ctrl: pushlit_fifo HEAD, 0xF0 pushlit_fifo HEAD, 0x14 RETURN release_alt: pushlit_fifo HEAD, 0xF0 pushlit_fifo HEAD, 0x11 RETURN release_shift: pushlit_fifo HEAD, 0xF0 pushlit_fifo HEAD, 0x12 RETURN toggle_ctrl: toggle KBD_CTRL, press_ctrl, release_ctrl toggle_alt: toggle KBD_ALT, press_alt, release_alt toggle_shift: toggle KBD_SHIFT, press_shift, release_shift undo_ctrlaltshift: ;toggle_led 6 ; MOVF MODE, W ; SUBLW d'79' ; if_set STATUS, Z ; GOTO continue ; if_set KBD_SHIFT ;We're dealing with a CAPSLOCK mode... CALL release_shift BCF KBD_SHIFT ;continue: ; if_set KBD_ALT CALL release_alt ; if_set KBD_CTRL CALL release_ctrl ;if_set KBD_ALT BCF KBD_ALT ;if_set KBD_CTRL BCF KBD_CTRL RETURN clear_1shot: MOVF PREVMODE,W ; get the previous mode MOVWF MODE BCF KBD_1SHOT RETURN led_blink: INCF LEDCOUNT,F ;Takes care of LED's, based on mode if_set KBD_SHIFT CALL shift_blink if_set KBD_CTRL CALL ctrl_blink if_set KBD_ALT CALL alt_blink MOVF MODE,W SUBLW d'31' if_set STATUS,Z GOTO numbers_blink MOVF MODE, W SUBLW d'26' if_set STATUS,Z GOTO keypad_blink MOVF MODE, W SUBLW d'17' if_set STATUS, Z GOTO function_blink BCF PORTC, 4 BCF PORTC, 5 BCF PORTC, 6 RETURN shift_blink: if_set KBD_1SHOT GOTO led4_slowblink led_on 4 RETURN ctrl_blink: GOTO led5_slowblink alt_blink: GOTO led5_fastblink numbers_blink: if_set KBD_1SHOT GOTO led6_slowblink led_on 6 RETURN keypad_blink: led_on 5 RETURN function_blink: goto led6_fastblink led4_slowblink: if_set LEDCOUNT,7 led_on 4 if_clear LEDCOUNT, 7 led_off 4 RETURN led5_slowblink: if_set LEDCOUNT,7 led_on 5 if_clear LEDCOUNT, 7 led_off 5 RETURN led5_fastblink: if_set LEDCOUNT,6 led_on 5 if_clear LEDCOUNT,6 led_off 5 RETURN led6_slowblink: if_set LEDCOUNT,7 led_on 6 if_clear LEDCOUNT,7 led_off 6 RETURN led6_fastblink: if_set LEDCOUNT,6 led_on 6 if_clear LEDCOUNT,6 led_off 6 RETURN ;; I need to have many tables; one for each mode. The shift mode ;; is not so bad; I can just save a bit. Similarly, the ;; I really need three tables. They will be sparse; each one ;; should have mostly DONTCARE entries. Functionality available from ;; every mode, including punctuation, cursor control, and so on, ;; will be programmed into the prototypical list. Then, we can call ;; Adam's key2scan table to translate the key codes into scan codes, ;; which we will send down the wire ;; In fact, we can pretty much drag and drop the functions from his ;; code. It's quite simple: ORG 0xB00 key2scan: RETLW DONTCARE ;0 RETLW 0x0E ;1 RETLW 0x16 ;2 RETLW 0x1E ;3 RETLW 0x26 ;4 RETLW 0x25 ;5 RETLW 0x2E ;6 RETLW 0x36 ;7 RETLW 0x3D ;8 RETLW 0x3E ;9 RETLW 0x46 ;10 RETLW 0x45 ;11 RETLW 0x4E ;12 RETLW 0x55 ;13 RETLW 0x5D ;14 (another backslash) RETLW 0x66 ;15 RETLW 0x0D ;16 RETLW 0x15 ;17 RETLW 0x1D ;18 RETLW 0x24 ;19 RETLW 0x2D ;20 RETLW 0x2C ;21 RETLW 0x35 ;22 RETLW 0x3C ;23 RETLW 0x43 ;24 RETLW 0x44 ;25 RETLW 0x4D ;26 RETLW 0x54 ;27 RETLW 0x5B ;28 RETLW 0x5D ;29 RETLW 0x58 ;30 RETLW 0x1C ;31 RETLW 0x1B ;32 RETLW 0x23 ;33 RETLW 0x2B ;34 RETLW 0x34 ;35 RETLW 0x33 ;36 RETLW 0x3B ;37 RETLW 0x42 ;38 RETLW 0x4B ;39 RETLW 0x4C ;40 RETLW 0x52 ;41 RETLW DONTCARE ;42 RETLW 0x5A ;43 RETLW 0x12 ;44 RETLW DONTCARE ;45 RETLW 0x1A ;46 RETLW 0x22 ;47 RETLW 0x21 ;48 RETLW 0x2A ;49 RETLW 0x32 ;50 RETLW 0x31 ;51 RETLW 0x3A ;52 RETLW 0x41 ;53 RETLW 0x49 ;54 RETLW 0x4A ;55 RETLW DONTCARE ;56 RETLW 0x59 ;57 RETLW 0x14 ;58 RETLW DONTCARE ;59 RETLW 0x11 ;60 RETLW 0x29 ;61 RETLW BEGIN_E0 | 0x11 ;62 RETLW DONTCARE ;63 RETLW BEGIN_E0 | 0x14 ;64 RETLW DONTCARE ;65 RETLW DONTCARE ;66 RETLW DONTCARE ;67 RETLW DONTCARE ;68 RETLW DONTCARE ;69 RETLW DONTCARE ;70 RETLW DONTCARE ;71 RETLW DONTCARE ;72 RETLW DONTCARE ;73 RETLW DONTCARE ;74 RETLW BEGIN_E0 | 0x70 ;75 RETLW BEGIN_E0 | 0x71 ;76 RETLW DONTCARE ;77 RETLW DONTCARE ;78 RETLW BEGIN_E0 | 0x6B ;79 RETLW BEGIN_E0 | 0x6C ;80 RETLW BEGIN_E0 | 0x69 ;81 RETLW DONTCARE ;82 RETLW BEGIN_E0 | 0x75 ;83 RETLW BEGIN_E0 | 0x72 ;84 RETLW BEGIN_E0 | 0x7D ;85 RETLW BEGIN_E0 | 0x7A ;86 RETLW DONTCARE ;87 RETLW DONTCARE ;88 RETLW BEGIN_E0 | 0x74 ;89 RETLW 0x77 ;90 RETLW 0x6C ;91 RETLW 0x6B ;92 RETLW 0x69 ;93 RETLW DONTCARE ;94 RETLW BEGIN_E0 | 0x4A ;95 RETLW 0x75 ;96 RETLW 0x73 ;97 RETLW 0x72 ;98 RETLW 0x70 ;99 RETLW 0x7C ;100 RETLW 0x7D ;101 RETLW 0x74 ;102 RETLW 0x7A ;103 RETLW 0x71 ;104 RETLW 0x7B ;105 RETLW 0x79 ;106 RETLW DONTCARE ;107 RETLW BEGIN_E0 | 0x5A ;108 RETLW DONTCARE ;109 RETLW 0x76 ;110 RETLW DONTCARE ;111 RETLW 0x05 ;112 RETLW 0x06 ;113 RETLW 0x04 ;114 RETLW 0x0C ;115 RETLW 0x03 ;116 RETLW 0x0B ;117 RETLW EXTENDED ;118 (see above) RETLW 0x0A ;119 RETLW 0x01 ;120 RETLW 0x09 ;121 RETLW 0x78 ;122 RETLW 0x07 ;123 RETLW EXTENDED ;124 RETLW 0x7E ;125 RETLW EXTENDED ;126 RETLW DONTCARE ;127 RETLW EXTENDED ;128 (press shift) RETLW EXTENDED ;129 (release shift) RETLW EXTENDED ;130 (press control) RETLW EXTENDED ;131 (release control) RETLW EXTENDED ;132 (press alt) RETLW EXTENDED ;133 (release alt) RETLW FUNCTION_EX ;134 (up) RETLW FUNCTION_EX ;135 (down) RETLW FUNCTION_EX ;136 (left) RETLW FUNCTION_EX ;137 (right) RETLW FUNCTION_EX ;138 (left click) RETLW FUNCTION_EX ;139 (right click) RETLW FUNCTION_EX ;140 (left toggle) RETLW FUNCTION_EX ;141 (right toggle) RETLW FUNCTION_EX ;142 (middle click) RETLW FUNCTION_EX ;143 (middle toggle) RETLW FUNCTION_EX ;144 (future) RETLW FUNCTION_EX ;145 (future) RETLW FUNCTION_EX ;146 (toggle ctrl) RETLW FUNCTION_EX ;147 (toggle alt) RETLW FUNCTION_EX ;148 (toggle shift) ORG 0xA00 extended_data: RETLW D'124' ; print screen / sysreq dt 0xE0, 0x12, 0xE0, 0x7C, 0xE0, 0xF0, 0x7C, 0xE0, 0xF0, 0x12, 0x00 RETLW D'126' ; break dt 0xE1, 0x14, 0x77, 0xE1, 0xF0, 0x14, 0xF0, 0x77, 0x00 RETLW D'118' ; comma, because it breaks my special case rule dt 0x83, 0xF0, 0x83, 0x00 RETLW D'128' ; press shift dt 0x12, 0x00 RETLW D'129' ; release shift dt 0xF0, 0x12, 0x00 RETLW D'130' ; press control dt 0x14, 0x00 RETLW D'131' ; release control dt 0xF0, 0x14, 0x00 RETLW D'132' ; press alt dt 0x11, 0x00 RETLW D'133' ; release alt dt 0xF0, 0x11, 0x00 RETLW 0 extended_data_end: ensure_table extended_data, extended_data_end ; a do- nothing function nop_function: RETURN ORG 0xC00 UUU: RETLW DONTCARE ;0 RETLW d'18' ;1 RETLW d'22' ;2 RETLW d'23' ;3 RETLW d'20' ;4 RETLW DONTCARE ;5 RETLW d'36' ;6 RETLW d'32' ;7 RETLW d'24' ;8 RETLW d'50' ;9 RETLW d'38' ;10 RETLW d'46' ;11 RETLW d'33' ;12 RETLW DONTCARE ;13 RETLW d'19' ;14 (another backslash) RETLW d'21' ;15 RETLW DONTCARE ;16 RETLW DONTCARE ;17 RETLW d'110' ;18 RETLW d'40' ;19 RETLW d'53' ;20 RETLW DONTCARE ;21 RETLW d'54' ;22 RETLW DONTCARE ;23 RETLW DONTCARE ;24 RETLW d'75' ;25 RETLW DONTCARE ;26 RETLW DONTCARE ;27 RETLW DONTCARE ;28 RETLW DONTCARE ;29 RETLW d'41' ;30 RETLW DONTCARE ;31 RETLW d'61' ;32 RETLW d'34' ;33 RETLW d'35' ;34 RETLW d'49' ;35 RETLW d'48' ;36 RETLW DONTCARE ;37 RETLW d'26' ;38 RETLW d'51' ;39 RETLW d'39' ;40 RETLW d'47' ;41 RETLW d'37' ;42 RETLW d'17' ;43 RETLW d'52' ;44 RETLW DONTCARE ;45 RETLW d'31' ;46 RETLW d'25' ;47 RETLW DONTCARE ;48 RETLW DONTCARE ;49 RETLW DONTCARE ;50 RETLW DONTCARE ;51 RETLW DONTCARE ;52 RETLW DONTCARE ;53 RETLW DONTCARE ;54 RETLW DONTCARE ;55 RETLW DONTCARE ;56 RETLW DONTCARE ;57 RETLW DONTCARE ;58 RETLW DONTCARE ;59 RETLW DONTCARE ;60 RETLW DONTCARE ;61 RETLW DONTCARE ;62 RETLW DONTCARE ;63 RETLW DONTCARE ;64 RETLW d'43' ;65 RETLW d'89' ;66 RETLW d'84' ;67 RETLW d'15' ;68 RETLW DONTCARE ;69 RETLW d'76' ;70 RETLW d'86' ;71 RETLW d'79' ;79 RETLW d'81' ;73 RETLW d'16' ;74 RETLW d'80' ;75 RETLW d'83' ;76 RETLW DONTCARE ;77 RETLW DONTCARE ;78 RETLW DONTCARE ;79 RETLW d'126' ;80 RETLW DONTCARE ;81 RETLW DONTCARE ;82 RETLW DONTCARE ;83 RETLW DONTCARE ;84 RETLW DONTCARE ;85 RETLW DONTCARE ;86 RETLW DONTCARE ;87 RETLW DONTCARE ;88 RETLW DONTCARE ;89 RETLW DONTCARE ;90 RETLW DONTCARE ;91 RETLW DONTCARE ;92 RETLW DONTCARE ;93 RETLW DONTCARE ;94 RETLW DONTCARE ;95 RETLW DONTCARE ;96 RETLW DONTCARE ;97 RETLW DONTCARE ;98 RETLW DONTCARE ;99 RETLW DONTCARE ;100 RETLW DONTCARE ;101 RETLW DONTCARE ;102 RETLW DONTCARE ;103 RETLW DONTCARE ;104 RETLW DONTCARE ;105 RETLW DONTCARE ;106 RETLW DONTCARE ;107 RETLW DONTCARE ;108 RETLW DONTCARE ;109 RETLW DONTCARE ;110 RETLW DONTCARE ;111 RETLW DONTCARE ;112 RETLW DONTCARE ;113 RETLW DONTCARE ;114 RETLW DONTCARE ;115 RETLW DONTCARE ;116 RETLW DONTCARE ;117 RETLW DONTCARE ;118 (see above) RETLW DONTCARE ;119 RETLW DONTCARE ;120 RETLW DONTCARE ;121 RETLW DONTCARE ;122 RETLW DONTCARE ;123 RETLW DONTCARE ;124 RETLW DONTCARE ;125 RETLW DONTCARE ;126 RETLW DONTCARE ;127 UUU_end: ensure_table UUU, UUU_end; ORG 0xD00 function_chord2key: RETLW DONTCARE ;0 RETLW d'116' ;1 RETLW d'115' ;2 RETLW DONTCARE ;3 RETLW d'114' ;4 RETLW DONTCARE ;5 RETLW DONTCARE ;6 RETLW DONTCARE ;7 RETLW d'113' ;8 RETLW DONTCARE ;9 RETLW DONTCARE ;10 RETLW DONTCARE ;11 RETLW DONTCARE ;12 RETLW DONTCARE ;13 RETLW DONTCARE ;14 RETLW DONTCARE ;15 RETLW DONTCARE ;16 RETLW DONTCARE ;17 RETLW d'110' ;18 RETLW d'40' ;19 RETLW d'53' ;20 RETLW DONTCARE ;21 RETLW d'54' ;22 RETLW DONTCARE ;23 RETLW DONTCARE ;24 RETLW d'75' ;25 RETLW DONTCARE ;26 RETLW DONTCARE ;27 RETLW DONTCARE ;28 RETLW DONTCARE ;29 RETLW d'41' ;30 RETLW DONTCARE ;31 RETLW d'112' ;32 RETLW d'120' ;33 RETLW d'118' ;34 RETLW d'123' ;35 RETLW d'118' ;36 RETLW DONTCARE ;37 RETLW d'122' ;38 RETLW DONTCARE ;39 RETLW DONTCARE ;40 RETLW DONTCARE ;41 RETLW DONTCARE ;42 RETLW DONTCARE ;43 RETLW d'121' ;44 RETLW DONTCARE ;45 RETLW DONTCARE ;46 RETLW DONTCARE ;47 RETLW DONTCARE ;48 RETLW DONTCARE ;49 RETLW DONTCARE ;50 RETLW DONTCARE ;51 RETLW DONTCARE ;52 RETLW DONTCARE ;53 RETLW DONTCARE ;54 RETLW DONTCARE ;55 RETLW DONTCARE ;56 RETLW DONTCARE ;57 RETLW DONTCARE ;58 RETLW DONTCARE ;59 RETLW DONTCARE ;60 RETLW DONTCARE ;61 RETLW DONTCARE ;62 RETLW DONTCARE ;63 RETLW DONTCARE ;64 RETLW d'43' ;65 RETLW d'89' ;66 RETLW d'84' ;67 RETLW d'15' ;68 RETLW DONTCARE ;69 RETLW d'76' ;70 RETLW d'86' ;71 RETLW d'79' ;79 RETLW d'81' ;73 RETLW d'16' ;74 RETLW d'80' ;75 RETLW D'83' ;76 RETLW DONTCARE ;77 RETLW DONTCARE ;78 RETLW DONTCARE ;79 RETLW d'126' ;80 RETLW DONTCARE ;81 RETLW DONTCARE ;82 RETLW DONTCARE ;83 RETLW DONTCARE ;84 RETLW DONTCARE ;85 RETLW DONTCARE ;86 RETLW DONTCARE ;87 RETLW DONTCARE ;88 RETLW DONTCARE ;89 RETLW DONTCARE ;90 RETLW DONTCARE ;91 RETLW DONTCARE ;92 RETLW DONTCARE ;93 RETLW DONTCARE ;94 RETLW DONTCARE ;95 RETLW DONTCARE ;96 RETLW DONTCARE ;97 RETLW DONTCARE ;98 RETLW DONTCARE ;99 RETLW DONTCARE ;100 RETLW DONTCARE ;101 RETLW DONTCARE ;102 RETLW DONTCARE ;103 RETLW DONTCARE ;104 RETLW DONTCARE ;105 RETLW DONTCARE ;106 RETLW DONTCARE ;107 RETLW DONTCARE ;108 RETLW DONTCARE ;109 RETLW DONTCARE ;110 RETLW DONTCARE ;111 RETLW DONTCARE ;112 RETLW DONTCARE ;113 RETLW DONTCARE ;114 RETLW DONTCARE ;115 RETLW DONTCARE ;116 RETLW DONTCARE ;117 RETLW DONTCARE ;118 RETLW DONTCARE ;119 RETLW DONTCARE ;120 RETLW DONTCARE ;121 RETLW DONTCARE ;122 RETLW DONTCARE ;123 RETLW DONTCARE ;124 RETLW DONTCARE ;125 RETLW DONTCARE ;126 RETLW DONTCARE ;127 function_chord2key_end: ensure_table function_chord2key, function_chord2key_end ORG 0xE00 keypad_chord2key: RETLW DONTCARE ;0 RETLW DONTCARE ;1 RETLW DONTCARE ;2 RETLW DONTCARE ;3 RETLW DONTCARE ;4 RETLW DONTCARE ;5 RETLW DONTCARE ;6 RETLW DONTCARE ;7 RETLW DONTCARE ;8 RETLW DONTCARE ;9 RETLW DONTCARE ;10 RETLW DONTCARE ;11 RETLW DONTCARE ;12 RETLW DONTCARE ;13 RETLW DONTCARE ;14 RETLW DONTCARE ;15 RETLW D'61' ;16 RETLW DONTCARE ;17 RETLW d'110' ;18 RETLW d'40' ;19 RETLW d'53' ;20 RETLW DONTCARE ;21 RETLW d'54' ;22 RETLW DONTCARE ;23 RETLW DONTCARE ;24 RETLW d'75' ;25 RETLW DONTCARE ;26 RETLW DONTCARE ;27 RETLW DONTCARE ;28 RETLW DONTCARE ;29 RETLW d'41' ;30 RETLW DONTCARE ;31 RETLW DONTCARE ;32 RETLW DONTCARE ;33 RETLW DONTCARE ;34 RETLW DONTCARE ;35 RETLW DONTCARE ;36 RETLW DONTCARE ;37 RETLW DONTCARE ;38 RETLW DONTCARE ;39 RETLW DONTCARE ;40 RETLW DONTCARE ;41 RETLW DONTCARE ;42 RETLW DONTCARE ;43 RETLW DONTCARE ;44 RETLW DONTCARE ;45 RETLW DONTCARE ;46 RETLW DONTCARE ;47 RETLW DONTCARE ;48 RETLW DONTCARE ;49 RETLW DONTCARE ;50 RETLW DONTCARE ;51 RETLW DONTCARE ;52 RETLW DONTCARE ;53 RETLW DONTCARE ;54 RETLW DONTCARE ;55 RETLW DONTCARE ;56 RETLW DONTCARE ;57 RETLW DONTCARE ;58 RETLW DONTCARE ;59 RETLW DONTCARE ;60 RETLW DONTCARE ;61 RETLW DONTCARE ;62 RETLW DONTCARE ;63 RETLW DONTCARE ;64 RETLW d'43' ;65 RETLW d'89' ;66 RETLW d'84' ;67 RETLW d'15' ;68 RETLW DONTCARE ;69 RETLW d'76' ;70 RETLW d'86' ;71 RETLW d'79' ;79 RETLW d'81' ;73 RETLW d'16' ;74 RETLW d'80' ;75 RETLW D'83' ;76 RETLW DONTCARE ;77 RETLW DONTCARE ;78 RETLW DONTCARE ;79 RETLW d'126' ;80 RETLW DONTCARE ;81 RETLW DONTCARE ;82 RETLW DONTCARE ;83 RETLW DONTCARE ;84 RETLW DONTCARE ;85 RETLW DONTCARE ;86 RETLW DONTCARE ;87 RETLW DONTCARE ;88 RETLW DONTCARE ;89 RETLW DONTCARE ;90 RETLW DONTCARE ;91 RETLW DONTCARE ;92 RETLW DONTCARE ;93 RETLW DONTCARE ;94 RETLW DONTCARE ;95 RETLW DONTCARE ;96 RETLW DONTCARE ;97 RETLW DONTCARE ;98 RETLW DONTCARE ;99 RETLW DONTCARE ;100 RETLW DONTCARE ;101 RETLW DONTCARE ;102 RETLW DONTCARE ;103 RETLW DONTCARE ;104 RETLW DONTCARE ;105 RETLW DONTCARE ;106 RETLW DONTCARE ;107 RETLW DONTCARE ;108 RETLW DONTCARE ;109 RETLW DONTCARE ;110 RETLW DONTCARE ;111 RETLW DONTCARE ;112 RETLW DONTCARE ;113 RETLW DONTCARE ;114 RETLW DONTCARE ;115 RETLW DONTCARE ;116 RETLW DONTCARE ;117 RETLW DONTCARE ;118 (see above) RETLW DONTCARE ;119 RETLW DONTCARE ;120 RETLW DONTCARE ;121 RETLW DONTCARE ;122 RETLW DONTCARE ;123 RETLW DONTCARE ;124 RETLW DONTCARE ;125 RETLW DONTCARE ;126 RETLW DONTCARE ;127 keypad_chord2key_end: ensure_table keypad_chord2key, keypad_chord2key_end ORG 0xF00 numbers_chord2key: RETLW DONTCARE ;0 RETLW d'6' ;1 RETLW d'5' ;2 RETLW DONTCARE ;3 RETLW d'4' ;4 RETLW DONTCARE ;5 RETLW DONTCARE ;6 RETLW D'12' ;7 RETLW D'3' ;8 RETLW D'29' ;9 RETLW DONTCARE ;10 RETLW D'1' ;11 RETLW D'55' ;12 RETLW DONTCARE ;13 RETLW D'13' ;14 RETLW DONTCARE ;15 RETLW D'61' ;16 RETLW DONTCARE ;17 RETLW d'110' ;18 RETLW d'40' ;19 RETLW d'53' ;20 RETLW DONTCARE ;21 RETLW d'54' ;22 RETLW DONTCARE ;23 RETLW DONTCARE ;24 RETLW d'75' ;25 RETLW DONTCARE ;26 RETLW DONTCARE ;27 RETLW DONTCARE ;28 RETLW DONTCARE ;29 RETLW d'41' ;30 RETLW DONTCARE ;31 RETLW D'2' ;32 RETLW D'10' ;33 RETLW D'9' ;34 RETLW D'28' ;35 RETLW D'8' ;36 RETLW DONTCARE ;37 RETLW DONTCARE ;38 RETLW D'27' ;39 RETLW D'7' ;40 RETLW DONTCARE ;41 RETLW DONTCARE ;42 RETLW DONTCARE ;43 RETLW DONTCARE ;44 RETLW DONTCARE ;45 RETLW DONTCARE ;46 RETLW D'11' ;47 RETLW DONTCARE ;48 RETLW DONTCARE ;49 RETLW DONTCARE ;50 RETLW DONTCARE ;51 RETLW DONTCARE ;52 RETLW DONTCARE ;53 RETLW DONTCARE ;54 RETLW DONTCARE ;55 RETLW DONTCARE ;56 RETLW DONTCARE ;57 RETLW DONTCARE ;58 RETLW DONTCARE ;59 RETLW DONTCARE ;60 RETLW DONTCARE ;61 RETLW DONTCARE ;62 RETLW DONTCARE ;63 RETLW DONTCARE ;64 RETLW d'43' ;65 RETLW d'89' ;66 RETLW d'84' ;67 RETLW d'15' ;68 RETLW DONTCARE ;69 RETLW d'76' ;70 RETLW d'86' ;71 RETLW d'79' ;79 RETLW d'81' ;73 RETLW d'16' ;74 RETLW d'80' ;75 RETLW D'83' ;76 RETLW DONTCARE ;77 RETLW DONTCARE ;78 RETLW DONTCARE ;79 RETLW d'126' ;80 RETLW DONTCARE ;81 RETLW DONTCARE ;82 RETLW DONTCARE ;83 RETLW DONTCARE ;84 RETLW DONTCARE ;85 RETLW DONTCARE ;86 RETLW DONTCARE ;87 RETLW DONTCARE ;88 RETLW DONTCARE ;89 RETLW DONTCARE ;90 RETLW DONTCARE ;91 RETLW DONTCARE ;92 RETLW DONTCARE ;93 RETLW DONTCARE ;94 RETLW DONTCARE ;95 RETLW DONTCARE ;96 RETLW DONTCARE ;97 RETLW DONTCARE ;98 RETLW DONTCARE ;99 RETLW DONTCARE ;100 RETLW DONTCARE ;101 RETLW DONTCARE ;102 RETLW DONTCARE ;103 RETLW DONTCARE ;104 RETLW DONTCARE ;105 RETLW DONTCARE ;106 RETLW DONTCARE ;107 RETLW DONTCARE ;108 RETLW DONTCARE ;109 RETLW DONTCARE ;110 RETLW DONTCARE ;111 RETLW DONTCARE ;112 RETLW DONTCARE ;113 RETLW DONTCARE ;114 RETLW DONTCARE ;115 RETLW DONTCARE ;116 RETLW DONTCARE ;117 RETLW DONTCARE ;118 RETLW DONTCARE ;119 RETLW DONTCARE ;120 RETLW DONTCARE ;121 RETLW DONTCARE ;122 RETLW DONTCARE ;123 RETLW DONTCARE ;124 RETLW DONTCARE ;125 RETLW DONTCARE ;126 RETLW DONTCARE ;127 END