aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ADB.txt134
-rw-r--r--adb.c180
-rw-r--r--adb.h18
-rw-r--r--adb/Makefile82
-rw-r--r--adb/README19
-rw-r--r--adb/config.h47
-rw-r--r--adb/keymap.c135
-rw-r--r--adb/matrix.c194
8 files changed, 809 insertions, 0 deletions
diff --git a/ADB.txt b/ADB.txt
new file mode 100644
index 000000000..b98cf6761
--- /dev/null
+++ b/ADB.txt
@@ -0,0 +1,134 @@
1ADB Protocol
2============
3
4Resources
5---------
6Apple IIgs Hardware Reference Second Edition [p80(Chapter6 p121)]
7 ftp://ftp.apple.asimov.net/pub/apple_II/documentation/Apple%20IIgs%20Hardware%20Reference.pdf
8ADB Keycode
9 http://72.0.193.250/Documentation/macppc/adbkeycodes/
10 http://m0115.web.fc2.com/m0115.jpg
11ADB Signaling
12 http://kbdbabel.sourceforge.net/doc/kbd_signaling_pcxt_ps2_adb.pdf
13ADB Overview & History
14 http://en.wikipedia.org/wiki/Apple_Desktop_Bus
15Microchip Application Note: ADB device(with code for PIC16C)
16 http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en011062
17AVR ATtiny2131 ADB to PS/2 converter(Japanese)
18 http://hp.vector.co.jp/authors/VA000177/html/KeyBoardA5DEA5CBA5A2II.html
19
20
21Pinouts
22-------
23 Female socket from the front
24
25 4o o3
26 2o o1
27 ==
28
29 1: Data
30 2: Power SW(low when press Power key)
31 3: Vcc(5V)
32 4: GND
33
34
35Commands
36--------
37 ADB command is 1byte and consists of 4bit-address, 2bit-command
38 type and 2bit-register. The commands are always sent by Host.
39
40 Command format:
41 7 6 5 4 3 2 1 0
42 | | | |------------ address
43 | |-------- command type
44 | |---- register
45
46 bits commands
47 ------------------------------------------------------
48 - - - - 0 0 0 0 Send Request(reset all devices)
49 A A A A 0 0 0 1 Flush(reset a device)
50 - - - - 0 0 1 0 Reserved
51 - - - - 0 0 1 1 Reserved
52 - - - - 0 1 - - Reserved
53 A A A A 1 0 R R Listen(write to a device)
54 A A A A 1 1 R R Talk(read from a device)
55
56 The command to read keycodes from keyboard is 0x2C which
57 consist of keyboard address 2 and Talk against register 0.
58
59 Address:
60 2: keyboard
61 3: mice
62
63 Registers:
64 0: application(keyobard/mice use to store its data.)
65 1: application
66 2: application
67 3: status and command
68
69
70Communication
71-------------
72 This is a minimum information for keyboard communication.
73 See "Resources" for detail.
74
75 Signaling:
76
77 ~~~~____________~~||||||||||||__~~~~~_~~|||||||||||||||__~~~~
78
79 |800us | |7 Command 0| | | |15-64 Data 0|Stopbit(0)
80 +Attention | | | +Startbit(1)
81 +Startbit(1) | +Tlt(140-260us)
82 +stopbit(0)
83
84 Bit cells:
85
86 bit0: ______~~~
87 65 :35us
88
89 bit1: ___~~~~~~
90 35 :65us
91
92 bit0 low time: 60-70% of bit cell(42-91us)
93 bit1 low time: 30-40% of bit cell(21-52us)
94 bit cell time: 70-130us
95 [from Apple IIgs Hardware Reference Second Edition]
96
97 Criterion for bit0/1:
98 After 55us if line is low/high then bit is 0/1.
99
100 Attention & start bit:
101 Host asserts low in 560-1040us then places start bit(1).
102
103 Tlt(Stop to Start):
104 Bus stays high in 140-260us then device places start bit(1).
105
106 Global reset:
107 Host asserts low in 2.8-5.2ms. All devices are forced to reset.
108
109 Send request from device(Srq):
110 Device can request to send at commad(Global only?) stop bit.
111 keep low for 300us to request.
112
113
114Keyboard data(register0)
115 This 16bit data can contains 2 keycodes and 2 released flags.
116 First keycode is palced in upper nibble. When one keyocode is sent,
117 lower nibble is 0xFF.
118 Release flag is 1 when key is released.
119
120 15 14 . . . . . 8 7 6 . . . . . 0
121 | |keycode1 | |keycode2
122 |released(1) |released(1)
123
124 Keycodes:
125 Scancode consists of 7bit keycode and 1bit release flag.
126 Device can send two keycodes at once. If just one keycode is sent
127 keycode1 contains it and keyocode2 is 0xFF.
128
129 Power switch:
130 You can read the state from PSW line(active low) however
131 the switch has a special scancode 0x7F7F, so you can
132 also read from Data line. It uses 0xFFFF for release scancode.
133
134END_OF_ADB
diff --git a/adb.c b/adb.c
new file mode 100644
index 000000000..e66a501b7
--- /dev/null
+++ b/adb.c
@@ -0,0 +1,180 @@
1#include <stdbool.h>
2#include <util/delay.h>
3#include <avr/io.h>
4#include "adb.h"
5
6
7static inline void data_lo(void);
8static inline void data_hi(void);
9static inline bool data_in(void);
10#ifdef ADB_PSW_BIT
11static inline void psw_lo(void);
12static inline void psw_hi(void);
13static inline bool psw_in(void);
14#endif
15
16static inline void attention(void);
17static inline void place_bit0(void);
18static inline void place_bit1(void);
19static inline void send_byte(uint8_t data);
20static inline bool read_bit(void);
21static inline uint8_t read_byte(void);
22static inline uint8_t wait_data_lo(uint8_t us);
23static inline uint8_t wait_data_hi(uint8_t us);
24
25
26void adb_host_init(void)
27{
28 data_hi();
29#ifdef ADB_PSW_BIT
30 psw_hi();
31#endif
32}
33
34#ifdef ADB_PSW_BIT
35bool adb_host_psw(void)
36{
37 return psw_in();
38}
39#endif
40
41uint16_t adb_host_kbd_recv(void)
42{
43 uint16_t data = 0;
44 attention();
45 send_byte(0x2C); // Addr:2, Cmd:talk(11), Reg:0(00)
46 place_bit0(); // Stopbit
47 if (!wait_data_lo(0xFF)) // Stop to Start(140-260us)
48 return 0; // No data to send
49 if (!read_bit()) // Startbit(1)
50 return -2;
51 data = read_byte();
52 data = (data<<8) | read_byte();
53 if (read_bit()) // Stopbit(0)
54 return -3;
55 return data;
56}
57
58
59static inline void data_lo()
60{
61 ADB_DDR |= (1<<ADB_DATA_BIT);
62 ADB_PORT &= ~(1<<ADB_DATA_BIT);
63}
64static inline void data_hi()
65{
66 ADB_PORT |= (1<<ADB_DATA_BIT);
67 ADB_DDR &= ~(1<<ADB_DATA_BIT);
68}
69static inline bool data_in()
70{
71 ADB_PORT |= (1<<ADB_DATA_BIT);
72 ADB_DDR &= ~(1<<ADB_DATA_BIT);
73 return ADB_PIN&(1<<ADB_DATA_BIT);
74}
75
76#ifdef ADB_PSW_BIT
77static inline void psw_lo()
78{
79 ADB_DDR |= (1<<ADB_PSW_BIT);
80 ADB_PORT &= ~(1<<ADB_PSW_BIT);
81}
82static inline void psw_hi()
83{
84 ADB_PORT |= (1<<ADB_PSW_BIT);
85 ADB_DDR &= ~(1<<ADB_PSW_BIT);
86}
87static inline bool psw_in()
88{
89 ADB_PORT |= (1<<ADB_PSW_BIT);
90 ADB_DDR &= ~(1<<ADB_PSW_BIT);
91 return ADB_PIN&(1<<ADB_PSW_BIT);
92}
93#endif
94
95static inline void attention(void)
96{
97 data_lo();
98 _delay_us(700);
99 place_bit1();
100}
101
102static inline void place_bit0(void)
103{
104 data_lo();
105 _delay_us(65);
106 data_hi();
107 _delay_us(35);
108}
109
110static inline void place_bit1(void)
111{
112 data_lo();
113 _delay_us(35);
114 data_hi();
115 _delay_us(65);
116}
117
118static inline void send_byte(uint8_t data)
119{
120 for (int i = 0; i < 8; i++) {
121 if (data&(0x80>>i))
122 place_bit1();
123 else
124 place_bit0();
125 }
126}
127
128static inline bool read_bit(void)
129{
130 // ADB Bit Cells
131 //
132 // bit0: ______~~~
133 // 65 :35us
134 //
135 // bit1: ___~~~~~~
136 // 35 :65us
137 //
138 // bit0 low time: 60-70% of bit cell(42-91us)
139 // bit1 low time: 30-40% of bit cell(21-52us)
140 // bit cell time: 70-130us
141 // [from Apple IIgs Hardware Reference Second Edition]
142 //
143 // After 55us if data line is low/high then bit is 0/1.
144 // Too simple to rely on?
145 bool bit;
146 wait_data_lo(75); // wait the beginning of bit cell
147 _delay_us(55);
148 bit = data_in();
149 wait_data_hi(36); // wait high part of bit cell
150 return bit;
151}
152
153static inline uint8_t read_byte(void)
154{
155 uint8_t data = 0;
156 for (int i = 0; i < 8; i++) {
157 data <<= 1;
158 if (read_bit())
159 data = data | 1;
160 }
161 return data;
162}
163
164static inline uint8_t wait_data_lo(uint8_t us)
165{
166 while (data_in() && us) {
167 _delay_us(1);
168 us--;
169 }
170 return us;
171}
172
173static inline uint8_t wait_data_hi(uint8_t us)
174{
175 while (!data_in() && us) {
176 _delay_us(1);
177 us--;
178 }
179 return us;
180}
diff --git a/adb.h b/adb.h
new file mode 100644
index 000000000..8f1673547
--- /dev/null
+++ b/adb.h
@@ -0,0 +1,18 @@
1#ifndef ADB_H
2#define ADB_H
3
4#include <stdbool.h>
5
6#if !(defined(ADB_PORT) && \
7 defined(ADB_PIN) && \
8 defined(ADB_DDR) && \
9 defined(ADB_DATA_BIT))
10# error "ADB port setting is required in config.h"
11#endif
12
13// ADB host
14void adb_host_init(void);
15bool adb_host_psw(void);
16uint16_t adb_host_kbd_recv(void);
17
18#endif
diff --git a/adb/Makefile b/adb/Makefile
new file mode 100644
index 000000000..c27c75e15
--- /dev/null
+++ b/adb/Makefile
@@ -0,0 +1,82 @@
1# Hey Emacs, this is a -*- makefile -*-
2#----------------------------------------------------------------------------
3# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
4#
5# Released to the Public Domain
6#
7# Additional material for this makefile was written by:
8# Peter Fleury
9# Tim Henigan
10# Colin O'Flynn
11# Reiner Patommel
12# Markus Pfaff
13# Sander Pool
14# Frederik Rouleau
15# Carlos Lamas
16#
17#----------------------------------------------------------------------------
18# On command line:
19#
20# make all = Make software.
21#
22# make clean = Clean out built project files.
23#
24# make coff = Convert ELF to AVR COFF.
25#
26# make extcoff = Convert ELF to AVR Extended COFF.
27#
28# make program = Download the hex file to the device, using avrdude.
29# Please customize the avrdude settings below first!
30#
31# make debug = Start either simulavr or avarice as specified for debugging,
32# with avr-gdb or avr-insight as the front end for debugging.
33#
34# make filename.s = Just compile filename.c into the assembler code only.
35#
36# make filename.i = Create a preprocessed source file for use in submitting
37# bug reports to the GCC project.
38#
39# To rebuild project do "make clean" then "make all".
40#----------------------------------------------------------------------------
41
42# Target file name (without extension).
43TARGET = tmk_adb
44
45# Directory common source filess exist
46COMMON_DIR = ..
47
48# Directory keyboard dependent files exist
49TARGET_DIR = .
50
51# keyboard dependent files
52TARGET_SRC = keymap.c \
53 matrix.c \
54 adb.c
55
56
57# MCU name, you MUST set this to match the board you are using
58# type "make clean" after changing this, so all files will be rebuilt
59#MCU = at90usb162 # Teensy 1.0
60MCU = atmega32u4 # Teensy 2.0
61#MCU = at90usb646 # Teensy++ 1.0
62#MCU = at90usb1286 # Teensy++ 2.0
63
64
65# Processor frequency.
66# Normally the first thing your program should do is set the clock prescaler,
67# so your program will run at the correct speed. You should also set this
68# variable to same clock speed. The _delay_ms() macro uses this, and many
69# examples use this variable to calculate timings. Do not add a "UL" here.
70F_CPU = 16000000
71
72
73# Build Options
74# comment out to disable the options.
75#
76MOUSEKEY_ENABLE = yes # Mouse keys
77#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
78USB_EXTRA_ENABLE = yes # Enhanced feature for Windows(Audio control and System control)
79#USB_NKRO_ENABLE = yes # USB Nkey Rollover
80
81
82include $(COMMON_DIR)/Makefile.common
diff --git a/adb/README b/adb/README
new file mode 100644
index 000000000..19d9f8fa1
--- /dev/null
+++ b/adb/README
@@ -0,0 +1,19 @@
1ADB to USB keyboard converter
2=============================
3
4This firmware converts ADB keyboard protocol to USB.
5
6Build
7-----
80. Connect ADB keyboard to Teensy by 3 lines(Vcc, GND, Data).
9 PSW line is optional. See ADB.txt for details.
101. Define following macros for ADB connection in config.h:
11 ADB_PORT
12 ADB_PIN
13 ADB_DDR
14 ADB_DATA_BIT
15 ADB_PSW_BIT
162. make
173. program Teensy.
18
19EOF
diff --git a/adb/config.h b/adb/config.h
new file mode 100644
index 000000000..099a24bfa
--- /dev/null
+++ b/adb/config.h
@@ -0,0 +1,47 @@
1#ifndef CONFIG_H
2#define CONFIG_H
3
4/* controller configuration */
5#include "controller_teensy.h"
6
7#define VENDOR_ID 0xFEED
8#define PRODUCT_ID 0x0ADB
9#define MANUFACTURER t.m.k.
10#define PRODUCT ADB keyboard converter
11#define DESCRIPTION convert ADB keyboard to USB
12
13/* matrix size */
14#define MATRIX_ROWS 16 // keycode bit: 3-0
15#define MATRIX_COLS 8 // keycode bit: 6-4
16/* define if matrix has ghost */
17//#define MATRIX_HAS_GHOST
18
19/* USB NKey Rollover */
20#ifdef USB_NKRO_ENABLE
21#endif
22
23/* mouse keys */
24#ifdef MOUSEKEY_ENABLE
25# define MOUSEKEY_DELAY_TIME 192
26#endif
27
28/* PS/2 mouse */
29#ifdef PS2_MOUSE_ENABLE
30# define PS2_CLOCK_PORT PORTF
31# define PS2_CLOCK_PIN PINF
32# define PS2_CLOCK_DDR DDRF
33# define PS2_CLOCK_BIT 0
34# define PS2_DATA_PORT PORTF
35# define PS2_DATA_PIN PINF
36# define PS2_DATA_DDR DDRF
37# define PS2_DATA_BIT 1
38#endif
39
40/* ADB port setting */
41#define ADB_PORT PORTF
42#define ADB_PIN PINF
43#define ADB_DDR DDRF
44#define ADB_DATA_BIT 0
45//#define ADB_PSW_BIT 1 // optional
46
47#endif
diff --git a/adb/keymap.c b/adb/keymap.c
new file mode 100644
index 000000000..8a9640482
--- /dev/null
+++ b/adb/keymap.c
@@ -0,0 +1,135 @@
1/*
2 * Keymap for ADB keyboard
3 */
4#include <stdint.h>
5#include <stdbool.h>
6#include <avr/pgmspace.h>
7#include "usb_keyboard.h"
8#include "usb_keycodes.h"
9#include "print.h"
10#include "debug.h"
11#include "util.h"
12#include "keymap_skel.h"
13
14
15// Convert physical keyboard layout to matrix array.
16// This is a macro to define keymap easily in keyboard layout form.
17
18// TODO: ADB to USB default keymap
19// TODO: keymap macro template for m0116/m0115
20/* Apple Keyboard m0116
21 K7F, \
22 K35, K12, K13, K14, K15, K17, K16, K1A, K1C, K19, K1D, K1B, K18, K33, K47, K51, K4B, K43, \
23 K30, K0C, K0D, K0E, K0F, K10, K11, K20, K22, K1F, K23, K21, K1E, K59, K5B, K5C, K4E, \
24 K36, K00, K01, K02, K03, K05, K04, K26, K28, K25, K29, K27, K24, K56, K57, K58, K45, \
25 K38, K06, K07, K08, K09, K0B, K2D, K2E, K2B, K2F, K2C, K7B, K53, K54, K55, \
26 K39, K3A, K37, K32, K31, K2A, K3B, K3C, K3D, K3E, K52, K41, K4C \
27*/
28
29/* no tenkey
30 K7F, \
31 K35, K12, K13, K14, K15, K17, K16, K1A, K1C, K19, K1D, K1B, K18, K33, \
32 K30, K0C, K0D, K0E, K0F, K10, K11, K20, K22, K1F, K23, K21, K1E, \
33 K36, K00, K01, K02, K03, K05, K04, K26, K28, K25, K29, K27, K24, \
34 K38, K06, K07, K08, K09, K0B, K2D, K2E, K2B, K2F, K2C, K7B, \
35 K39, K3A, K37, K32, K31, K2A, K3B, K3C, K3D, K3E \
36*/
37#define KEYMAP( \
38 K7F, \
39 K35, K12, K13, K14, K15, K17, K16, K1A, K1C, K19, K1D, K1B, K18, K33, \
40 K30, K0C, K0D, K0E, K0F, K10, K11, K20, K22, K1F, K23, K21, K1E, \
41 K36, K00, K01, K02, K03, K05, K04, K26, K28, K25, K29, K27, K24, \
42 K38, K06, K07, K08, K09, K0B, K2D, K2E, K2B, K2F, K2C, K7B, \
43 K39, K3A, K37, K32, K31, K2A, K3B, K3C, K3D, K3E \
44) { \
45 { K00, K01, K02, K03, K04, K05, K06, K07 }, \
46 { K08, K09, 000, K0B, K0C, K0D, K0E, K0F }, \
47 { K10, K11, K12, K13, K14, K15, K16, K17 }, \
48 { K18, K19, K1A, K1B, K1C, K1D, K1E, K1F }, \
49 { K20, K21, K22, K23, K24, K25, K26, K27 }, \
50 { K28, K29, K2A, K2B, K2C, K2D, K2E, K2F }, \
51 { K30, K31, K32, K33, 000, K35, K36, K37 }, \
52 { K38, K39, K3A, K3B, K3C, K3D, K3E, 000 }, \
53 { 000, 000, 000, 000, 000, 000, 000, 000 }, \
54 { 000, 000, 000, 000, 000, 000, 000, 000 }, \
55 { 000, 000, 000, 000, 000, 000, 000, 000 }, \
56 { 000, 000, 000, 000, 000, 000, 000, 000 }, \
57 { 000, 000, 000, 000, 000, 000, 000, 000 }, \
58 { 000, 000, 000, 000, 000, 000, 000, 000 }, \
59 { 000, 000, 000, 000, 000, 000, 000, 000 }, \
60 { 000, 000, 000, K7B, 000, 000, 000, K7F }, \
61}
62
63#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)]))
64
65
66// Assign Fn key(0-7) to a layer to which switch with the Fn key pressed.
67static const uint8_t PROGMEM fn_layer[] = {
68 0, // FN_0
69 0, // FN_1
70 0, // FN_2
71 0, // FN_3
72 0, // FN_4
73 0, // FN_5
74 0, // FN_6
75 0 // FN_7
76};
77
78// Assign Fn key(0-7) to a keycode sent when release Fn key without use of the layer.
79// See layer.c for details.
80static const uint8_t PROGMEM fn_keycode[] = {
81 KB_NO, // FN_0
82 KB_NO, // FN_1
83 KB_NO, // FN_2
84 KB_NO, // FN_3
85 KB_NO, // FN_4
86 KB_NO, // FN_5
87 KB_NO, // FN_6
88 KB_NO // FN_7
89};
90
91static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
92 /* Layer 0: Default Layer
93 * ,---------------------------------------------------------.
94 * |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backs|
95 * |---------------------------------------------------------|
96 * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| |
97 * |-----------------------------------------------------' |
98 * |Contro| A| S| D| F| G| H| J| K| L|Fn3| '|Return|
99 * |---------------------------------------------------------|
100 * |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift |
101 * |---------------------------------------------------------|
102 * |Shi|Alt|Gui l `| | \|Lef|Rig|Dow|Up |
103 * `---------------------------------------------------------'
104 */
105 KEYMAP(KB_PWR, \
106 KB_ESC, KB_1, KB_2, KB_3, KB_4, KB_5, KB_6, KB_7, KB_8, KB_9, KB_0, KB_MINS,KB_EQL, KB_BSPC, \
107 KB_TAB, KB_Q, KB_W, KB_E, KB_R, KB_T, KB_Y, KB_U, KB_I, KB_O, KB_P, KB_LBRC,KB_RBRC, \
108 KB_LCTL,KB_A, KB_S, KB_D, KB_F, KB_G, KB_H, KB_J, KB_K, KB_L, KB_SCLN,KB_QUOT,KB_ENT, \
109 KB_LSFT,KB_Z, KB_X, KB_C, KB_V, KB_B, KB_N, KB_M, KB_COMM,KB_DOT, KB_SLSH,KB_RSFT, \
110 KB_LSFT,KB_LALT,KB_LGUI,KB_GRV, KB_SPC, KB_BSLS,KB_LEFT,KB_RGHT,KB_DOWN,KB_UP),
111
112};
113
114
115uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col)
116{
117 return KEYCODE(layer, row, col);
118}
119
120uint8_t keymap_fn_layer(uint8_t fn_bits)
121{
122 return pgm_read_byte(&fn_layer[biton(fn_bits)]);
123}
124
125uint8_t keymap_fn_keycode(uint8_t fn_bits)
126{
127 return pgm_read_byte(&fn_keycode[(biton(fn_bits))]);
128}
129
130// define a condition to enter special function mode
131bool keymap_is_special_mode(uint8_t fn_bits)
132{
133 //return (usb_keyboard_mods == (BIT_LCTRL | BIT_LSHIFT | BIT_LALT | BIT_LGUI));
134 return (usb_keyboard_mods == (BIT_RSHIFT));
135}
diff --git a/adb/matrix.c b/adb/matrix.c
new file mode 100644
index 000000000..d0643371e
--- /dev/null
+++ b/adb/matrix.c
@@ -0,0 +1,194 @@
1/*
2 * scan matrix
3 */
4#include <stdint.h>
5#include <stdbool.h>
6#include <avr/io.h>
7#include <util/delay.h>
8#include "print.h"
9#include "util.h"
10#include "debug.h"
11#include "adb.h"
12#include "matrix_skel.h"
13
14
15#if (MATRIX_COLS > 16)
16# error "MATRIX_COLS must not exceed 16"
17#endif
18#if (MATRIX_ROWS > 255)
19# error "MATRIX_ROWS must not exceed 255"
20#endif
21
22
23static bool _matrix_is_modified = false;
24
25// matrix state buffer(1:on, 0:off)
26#if (MATRIX_COLS <= 8)
27static uint8_t *matrix;
28static uint8_t _matrix0[MATRIX_ROWS];
29#else
30static uint16_t *matrix;
31static uint16_t _matrix0[MATRIX_ROWS];
32#endif
33
34#ifdef MATRIX_HAS_GHOST
35static bool matrix_has_ghost_in_row(uint8_t row);
36#endif
37static void _register_key(uint8_t key);
38
39
40inline
41uint8_t matrix_rows(void)
42{
43 return MATRIX_ROWS;
44}
45
46inline
47uint8_t matrix_cols(void)
48{
49 return MATRIX_COLS;
50}
51
52void matrix_init(void)
53{
54 adb_host_init();
55
56 // initialize matrix state: all keys off
57 for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
58 matrix = _matrix0;
59
60 print_enable = true;
61 debug_enable = true;
62 debug_matrix = true;
63 debug_keyboard = true;
64 debug_mouse = true;
65 print("debug enabled.\n");
66 return;
67}
68
69uint8_t matrix_scan(void)
70{
71 uint16_t codes;
72 uint8_t key0, key1;
73
74 _matrix_is_modified = false;
75
76 codes = adb_host_kbd_recv();
77 key0 = codes>>8;
78 key1 = codes&0xFF;
79 if (debug_matrix) {
80 //print("adb_host_kbd_recv: "); phex16(codes); print("\n");
81 }
82
83 if (codes == 0) { // no keys
84 return 0;
85 } else if (key0 == 0xFF && key1 != 0xFF) { // error
86 return codes&0xFF;
87 } else {
88 _matrix_is_modified = true;
89 _register_key(key0);
90 if (key1 != 0xFF) // key1 is 0xFF when no second key.
91 _register_key(key1);
92 }
93
94 return 1;
95}
96
97bool matrix_is_modified(void)
98{
99 return _matrix_is_modified;
100}
101
102inline
103bool matrix_has_ghost(void)
104{
105#ifdef MATRIX_HAS_GHOST
106 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
107 if (matrix_has_ghost_in_row(i))
108 return true;
109 }
110#endif
111 return false;
112}
113
114inline
115bool matrix_is_on(uint8_t row, uint8_t col)
116{
117 return (matrix[row] & (1<<col));
118}
119
120inline
121#if (MATRIX_COLS <= 8)
122uint8_t matrix_get_row(uint8_t row)
123#else
124uint16_t matrix_get_row(uint8_t row)
125#endif
126{
127 return matrix[row];
128}
129
130void matrix_print(void)
131{
132#if (MATRIX_COLS <= 8)
133 print("\nr/c 01234567\n");
134#else
135 print("\nr/c 0123456789ABCDEF\n");
136#endif
137 for (uint8_t row = 0; row < matrix_rows(); row++) {
138 phex(row); print(": ");
139#if (MATRIX_COLS <= 8)
140 pbin_reverse(matrix_get_row(row));
141#else
142 pbin_reverse16(matrix_get_row(row));
143#endif
144#ifdef MATRIX_HAS_GHOST
145 if (matrix_has_ghost_in_row(row)) {
146 print(" <ghost");
147 }
148#endif
149 print("\n");
150 }
151}
152
153uint8_t matrix_key_count(void)
154{
155 uint8_t count = 0;
156 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
157#if (MATRIX_COLS <= 8)
158 count += bitpop(matrix[i]);
159#else
160 count += bitpop16(matrix[i]);
161#endif
162 }
163 return count;
164}
165
166#ifdef MATRIX_HAS_GHOST
167inline
168static bool matrix_has_ghost_in_row(uint8_t row)
169{
170 // no ghost exists in case less than 2 keys on
171 if (((matrix[row] - 1) & matrix[row]) == 0)
172 return false;
173
174 // ghost exists in case same state as other row
175 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
176 if (i != row && (matrix[i] & matrix[row]) == matrix[row])
177 return true;
178 }
179 return false;
180}
181#endif
182
183inline
184static void _register_key(uint8_t key)
185{
186 uint8_t col, row;
187 col = key&0x07;
188 row = (key>>3)&0x0F;
189 if (key&0x80) {
190 matrix[row] &= ~(1<<col);
191 } else {
192 matrix[row] |= (1<<col);
193 }
194}