diff options
author | tmk <nobody@nowhere> | 2011-12-14 12:13:32 +0900 |
---|---|---|
committer | tmk <nobody@nowhere> | 2011-12-14 13:33:05 +0900 |
commit | 3f0289e66678af8c2d1f001ccb9cb34ccfba7c5c (patch) | |
tree | 98519c2a10124308bb9e2f731712ed5379642599 | |
parent | e2afc305edc7133e42cab8c2a30b1e214f4926f8 (diff) | |
download | firmware-3f0289e66678af8c2d1f001ccb9cb34ccfba7c5c.tar.gz firmware-3f0289e66678af8c2d1f001ccb9cb34ccfba7c5c.tar.bz2 firmware-3f0289e66678af8c2d1f001ccb9cb34ccfba7c5c.zip |
Added protocol support for Macintosh keyboard M0110.
-rw-r--r-- | m0110.c | 304 | ||||
-rw-r--r-- | m0110.h | 73 | ||||
-rw-r--r-- | m0110_usb/Makefile | 52 | ||||
-rw-r--r-- | m0110_usb/README | 55 | ||||
-rw-r--r-- | m0110_usb/config.h | 62 | ||||
-rwxr-xr-x | m0110_usb/doc/m0110.jpg | bin | 0 -> 49360 bytes | |||
-rwxr-xr-x | m0110_usb/doc/teensy.jpg | bin | 0 -> 50081 bytes | |||
-rw-r--r-- | m0110_usb/keymap.c | 118 | ||||
-rw-r--r-- | m0110_usb/led.c | 24 | ||||
-rw-r--r-- | m0110_usb/matrix.c | 193 |
10 files changed, 881 insertions, 0 deletions
diff --git a/m0110.c b/m0110.c new file mode 100644 index 000000000..725675ed8 --- /dev/null +++ b/m0110.c @@ -0,0 +1,304 @@ +/* +Copyright 2011 Jun WAKO <wakojun@gmail.com> + +This software is licensed with a Modified BSD License. +All of this is supposed to be Free Software, Open Source, DFSG-free, +GPL-compatible, and OK to use in both free and proprietary applications. +Additions and corrections to this file are welcome. + + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +* Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdbool.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <util/delay.h> +#include "m0110.h" +#include "debug.h" + + +static inline void clock_lo(void); +static inline void clock_hi(void); +static inline bool clock_in(void); +static inline void data_lo(void); +static inline void data_hi(void); +static inline bool data_in(void); +static inline uint16_t wait_clock_lo(uint16_t us); +static inline uint16_t wait_clock_hi(uint16_t us); +static inline uint16_t wait_data_lo(uint16_t us); +static inline uint16_t wait_data_hi(uint16_t us); +static inline void idle(void); +static inline void request(void); + + +/* +Primitive M0110 Library for AVR +============================== + + +Signaling +--------- +CLOCK is always from KEYBOARD. DATA are sent with MSB first. + +1) IDLE: both line is high. + CLOCK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + DATA ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +2) KEYBOARD->HOST: HOST reads bit on rising edge. + CLOCK ~~~~~~~~~~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~~~~~~~~~ + DATA ~~~~~~~~~~~~X777777X666666X555555X444444X333333X222222X111111X000000X~~~~~~~ + <--> 160us(clock low) + <---> 180us(clock high) + +3) HOST->KEYBOARD: HOST asserts bit on falling edge. + CLOCK ~~~~~~~~~~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~~~~~~~~~ + DATA ~~~~~~|_____X777777X666666X555555X444444X333333X222222X111111X000000X~~~~~~~ + <----> 840us(request to send by host) <-> 80us(hold DATA) + <--> 180us(clock low) + <---> 220us(clock high) + + +Protocol +-------- +COMMAND: + Inquiry 0x10 get key event + Instant 0x12 get key event + Model 0x14 get model number(M0110 responds with 0x09) + bit 7 1 if another device connected(used when keypad exists?) + bit4-6 next device model number + bit1-3 keyboard model number + bit 0 always 1 + Test 0x16 test(ACK:0x7D/NAK:0x77) + +KEY EVENT: + bit 7 key state(0:press 1:release) + bit 6-1 scan code + bit 0 always 1 + To get scan code, use ((bits&(1<<7)) | ((bits&7F))>>1). + +SCAN CODE: + M0110A + ,---------------------------------------------------------. + | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backs| + |---------------------------------------------------------| + |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| + |---------------------------------------------------------| + |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return| + |---------------------------------------------------------| + |Shift | Z| X| C| V| B| N| M| ,| ,| /| | + `---------------------------------------------------------' + |Opt|Mac | Space |Enter|Opt| + `------------------------------------------------' + ,---------------------------------------------------------. + | 32| 12| 13| 14| 15| 17| 16| 1A| 1C| 19| 1D| 1B| 18| 33| + |---------------------------------------------------------| + | 30| 0C| 0D| 0E| 0F| 10| 11| 20| 22| 1F| 23| 21| 1E| 2A| + |---------------------------------------------------------| + | 39| 00| 01| 02| 03| 05| 04| 26| 28| 25| 29| 27| 24| + |---------------------------------------------------------| + | 38| 06| 07| 08| 09| 0B| 2D| 2E| 2B| 2F| 2C| 38| + `---------------------------------------------------------' + | 3A| 37| 31 | 34| 3A| + `------------------------------------------------' + + +References +---------- +Protocol: + http://www.mac.linux-m68k.org/devel/plushw.php +Connector: + http://www.kbdbabel.org/conn/kbd_connector_macplus.png +Signaling: + http://www.kbdbabel.org/signaling/kbd_signaling_mac.png + http://typematic.blog.shinobi.jp/Entry/14/ +Scan Codes: + http://m0115.web.fc2.com/m0110.jpg + http://m0115.web.fc2.com/m0110a.jpg +*/ + + +#define WAIT(stat, us, err) do { \ + if (!wait_##stat(us)) { \ + m0110_error = err; \ + goto ERROR; \ + } \ +} while (0) + + +uint8_t m0110_error = 0; + + +void m0110_init(void) +{ + uint8_t data; + idle(); + _delay_ms(255); + + m0110_send(M0110_MODLE); + data = m0110_recv(); + print("m0110_init model: "); phex(data); print("\n"); + + m0110_send(M0110_TEST); + data = m0110_recv(); + print("m0110_init test: "); phex(data); print("\n"); +} + +uint8_t m0110_send(uint8_t data) +{ + m0110_error = 0; + + request(); + WAIT(clock_lo, 1000, 0); + for (uint8_t bit = 0x80; bit; bit >>= 1) { + WAIT(clock_lo, 250, 3); + _delay_us(15); + if (data&bit) { + data_hi(); + } else { + data_lo(); + } + WAIT(clock_hi, 200, 4); + } + _delay_us(100); // hold last bit for 80us + idle(); + return 1; +ERROR: + if (m0110_error) { + print("m0110_send err: "); phex(m0110_error); print("\n"); + } + idle(); + return 0; +} + +uint8_t m0110_recv(void) +{ + uint8_t data = 0; + m0110_error = 0; + + WAIT(clock_lo, -1, 0); // need 250ms? insted 0xffff(16bit max)us + for (uint8_t i = 0; i < 8; i++) { + data <<= 1; + WAIT(clock_lo, 200, 2); + WAIT(clock_hi, 200, 3); + if (data_in()) { + data |= 1; + } + } + idle(); + print("m0110_send recv data: "); phex(data); print("\n"); + return data; +ERROR: + if (m0110_error) { + print("m0110_recv err: "); phex(m0110_error); print("\n"); + } + idle(); + return 0xFF; +} + +uint8_t m0110_recv_key(void) +{ + uint8_t key; + m0110_send(M0110_INQUIRY); + key = m0110_recv(); + if (key == 0xFF || key == M0110_NULL) + return M0110_NULL; + else + return (key&(1<<7) | (key&0x7F)>>1); +} + + +static inline void clock_lo() +{ + M0110_CLOCK_PORT &= ~(1<<M0110_CLOCK_BIT); + M0110_CLOCK_DDR |= (1<<M0110_CLOCK_BIT); +} +static inline void clock_hi() +{ + /* input with pull up */ + M0110_CLOCK_DDR &= ~(1<<M0110_CLOCK_BIT); + M0110_CLOCK_PORT |= (1<<M0110_CLOCK_BIT); +} +static inline bool clock_in() +{ + M0110_CLOCK_DDR &= ~(1<<M0110_CLOCK_BIT); + M0110_CLOCK_PORT |= (1<<M0110_CLOCK_BIT); + _delay_us(1); + return M0110_CLOCK_PIN&(1<<M0110_CLOCK_BIT); +} +static inline void data_lo() +{ + M0110_DATA_PORT &= ~(1<<M0110_DATA_BIT); + M0110_DATA_DDR |= (1<<M0110_DATA_BIT); +} +static inline void data_hi() +{ + /* input with pull up */ + M0110_DATA_DDR &= ~(1<<M0110_DATA_BIT); + M0110_DATA_PORT |= (1<<M0110_DATA_BIT); +} +static inline bool data_in() +{ + M0110_DATA_DDR &= ~(1<<M0110_DATA_BIT); + M0110_DATA_PORT |= (1<<M0110_DATA_BIT); + _delay_us(1); + return M0110_DATA_PIN&(1<<M0110_DATA_BIT); +} + +static inline uint16_t wait_clock_lo(uint16_t us) +{ + while (clock_in() && us) { asm(""); _delay_us(1); us--; } + return us; +} +static inline uint16_t wait_clock_hi(uint16_t us) +{ + while (!clock_in() && us) { asm(""); _delay_us(1); us--; } + return us; +} +static inline uint16_t wait_data_lo(uint16_t us) +{ + while (data_in() && us) { asm(""); _delay_us(1); us--; } + return us; +} +static inline uint16_t wait_data_hi(uint16_t us) +{ + while (!data_in() && us) { asm(""); _delay_us(1); us--; } + return us; +} + +static inline void idle(void) +{ + clock_hi(); + data_hi(); +} + +static inline void request(void) +{ + clock_hi(); + data_lo(); +} diff --git a/m0110.h b/m0110.h new file mode 100644 index 000000000..fe2e91227 --- /dev/null +++ b/m0110.h @@ -0,0 +1,73 @@ +/* +Copyright 2011 Jun WAKO <wakojun@gmail.com> + +This software is licensed with a Modified BSD License. +All of this is supposed to be Free Software, Open Source, DFSG-free, +GPL-compatible, and OK to use in both free and proprietary applications. +Additions and corrections to this file are welcome. + + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +* Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef M0110_H +#define M0110_H + + +/* port settings for clock and data line */ +#if !(defined(M0110_CLOCK_PORT) && \ + defined(M0110_CLOCK_PIN) && \ + defined(M0110_CLOCK_DDR) && \ + defined(M0110_CLOCK_BIT)) +# error "M0110 clock port setting is required in config.h" +#endif + +#if !(defined(M0110_DATA_PORT) && \ + defined(M0110_DATA_PIN) && \ + defined(M0110_DATA_DDR) && \ + defined(M0110_DATA_BIT)) +# error "M0110 data port setting is required in config.h" +#endif + +#define M0110_INQUIRY 0x10 +#define M0110_INSTNAT 0x14 +#define M0110_MODLE 0x16 +#define M0110_TEST 0x36 + +#define M0110_NULL 0x7B + + +extern uint8_t m0110_error; + +/* host role */ +void m0110_host_init(void); +uint8_t m0110_send(uint8_t data); +uint8_t m0110_recv(void); +uint8_t m0110_recv_key(void); + +#endif diff --git a/m0110_usb/Makefile b/m0110_usb/Makefile new file mode 100644 index 000000000..8c8460c80 --- /dev/null +++ b/m0110_usb/Makefile @@ -0,0 +1,52 @@ +# Target file name (without extension). +TARGET = m0110 + +# Directory common source filess exist +COMMON_DIR = .. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# keyboard dependent files +SRC = main.c \ + keymap.c \ + matrix.c \ + led.c \ + m0110.c + +CONFIG_H = config.h + + +# MCU name, you MUST set this to match the board you are using +# type "make clean" after changing this, so all files will be rebuilt +#MCU = at90usb162 # Teensy 1.0 +MCU = atmega32u4 # Teensy 2.0 +#MCU = at90usb646 # Teensy++ 1.0 +#MCU = at90usb1286 # Teensy++ 2.0 + + +# Processor frequency. +# Normally the first thing your program should do is set the clock prescaler, +# so your program will run at the correct speed. You should also set this +# variable to same clock speed. The _delay_ms() macro uses this, and many +# examples use this variable to calculate timings. Do not add a "UL" here. +F_CPU = 16000000 + + +# Build Options +# *Comment out* to disable the options. +# +#MOUSEKEY_ENABLE = yes # Mouse keys +#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support +#EXTRAKEY_ENABLE = yes # Audio control and System control +#NKRO_ENABLE = yes # USB Nkey Rollover + + + +#---------------- Programming Options -------------------------- +PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex + + + +include $(COMMON_DIR)/pjrc.mk +include $(COMMON_DIR)/common.mk diff --git a/m0110_usb/README b/m0110_usb/README new file mode 100644 index 000000000..4122edb28 --- /dev/null +++ b/m0110_usb/README @@ -0,0 +1,55 @@ +M0110 to USB keyboard converter +=============================== +This firmware converts protocol for Apple Machintosh Keybard M0110. + + +Connection +---------- +You need 4P4C plug and cable to connect Teensy into M0110. +Teensy port F0 is assigned for CLOCK line and F1 for DATA by default, you can change pin configuration with editing config.h.. + +Plug: + http://en.wikipedia.org/wiki/Modular_connector#4P4C + +Pinout: + http://www.kbdbabel.org/conn/kbd_connector_macplus.png + 1(Black): GND + 2(Red): CLOCK + 3(Green): DATA + 4(Yellow): +5V + + + +Build Frimware +-------------- +Optionally edit Makefile and config.h for build options, pin configuration or MCU. + +$ cd m0110_usb +$ make +and program your Teensy with loader. + + + +Keymap +------ +You can change a keymap by editing code of keymap.c like following. +How to define the keymap is probably obvious. You can find key symbols in usb_keycodes.h. + +This is a default keymap for M0110. +,---------------------------------------------------------. +| `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Bacpa| +|---------------------------------------------------------| +|Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| +|---------------------------------------------------------| +|CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return| +|---------------------------------------------------------| +|Shift | Z| X| C| V| B| N| M| ,| ,| /|Shift | +`---------------------------------------------------------' + |Opt|Alt | Space |Alt |Opt| + `-----------------------------------------------' + + +Notes +----- + +EOF diff --git a/m0110_usb/config.h b/m0110_usb/config.h new file mode 100644 index 000000000..c12e0738d --- /dev/null +++ b/m0110_usb/config.h @@ -0,0 +1,62 @@ +/* +Copyright 2011 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef CONFIG_H +#define CONFIG_H + +/* controller configuration */ +#include "controller_teensy.h" + + +#define VENDOR_ID 0xFEED +#define PRODUCT_ID 0x0110 +#define MANUFACTURER t.m.k. +#define PRODUCT M0110 keyboard converter +#define DESCRIPTION convert M0110 keyboard to USB + + +/* matrix size */ +#define MATRIX_ROWS 8 +#define MATRIX_COLS 8 + +/* Locking Caps Lock support */ +//#define MATRIX_HAS_LOCKING_CAPS + +/* key combination for command */ +#define IS_COMMAND() ( \ + keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_LCTRL) | MOD_BIT(KB_LALT) | MOD_BIT(KB_LGUI)) || \ + keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_RSHIFT)) \ +) + + +/* mouse keys */ +#ifdef MOUSEKEY_ENABLE +# define MOUSEKEY_DELAY_TIME 192 +#endif + + +/* ports */ +#define M0110_CLOCK_PORT PORTF +#define M0110_CLOCK_PIN PINF +#define M0110_CLOCK_DDR DDRF +#define M0110_CLOCK_BIT 0 +#define M0110_DATA_PORT PORTF +#define M0110_DATA_PIN PINF +#define M0110_DATA_DDR DDRF +#define M0110_DATA_BIT 1 + +#endif diff --git a/m0110_usb/doc/m0110.jpg b/m0110_usb/doc/m0110.jpg Binary files differnew file mode 100755 index 000000000..ef9a123ab --- /dev/null +++ b/m0110_usb/doc/m0110.jpg diff --git a/m0110_usb/doc/teensy.jpg b/m0110_usb/doc/teensy.jpg Binary files differnew file mode 100755 index 000000000..96e93e7e2 --- /dev/null +++ b/m0110_usb/doc/teensy.jpg diff --git a/m0110_usb/keymap.c b/m0110_usb/keymap.c new file mode 100644 index 000000000..24fe6cd47 --- /dev/null +++ b/m0110_usb/keymap.c @@ -0,0 +1,118 @@ +/* +Copyright 2011 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Keymap for ADB keyboard + */ +#include <stdint.h> +#include <stdbool.h> +#include <avr/pgmspace.h> +#include "usb_keyboard.h" +#include "usb_keycodes.h" +#include "print.h" +#include "debug.h" +#include "util.h" +#include "keymap.h" + + +#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)])) + +// Convert physical keyboard layout to matrix array. +// This is a macro to define keymap easily in keyboard layout form. +// TODO: layout for M0110A +/* M0110 */ +#define KEYMAP( \ + K32,K12,K13,K14,K15,K17,K16,K1A,K1C,K19,K1D,K1B,K18,K33, \ + K30,K0C,K0D,K0E,K0F,K11,K10,K20,K22,K1F,K23,K21,K1E,K2A, \ + K39,K00,K01,K02,K03,K05,K04,K26,K28,K25,K29,K27, K24, \ + K38,K06,K07,K08,K09,K0B,K2D,K2E,K2B,K2F,K2C, \ + K3A,K37, K31, K34 \ +) { \ + { KB_##K00, KB_##K01, KB_##K02, KB_##K03, KB_##K04, KB_##K05, KB_##K06, KB_##K07 }, \ + { KB_##K08, KB_##K09, KB_NO, KB_##K0B, KB_##K0C, KB_##K0D, KB_##K0E, KB_##K0F }, \ + { KB_##K10, KB_##K11, KB_##K12, KB_##K13, KB_##K14, KB_##K15, KB_##K16, KB_##K17 }, \ + { KB_##K18, KB_##K19, KB_##K1A, KB_##K1B, KB_##K1C, KB_##K1D, KB_##K1E, KB_##K1F }, \ + { KB_##K20, KB_##K21, KB_##K22, KB_##K23, KB_##K24, KB_##K25, KB_##K26, KB_##K27 }, \ + { KB_##K28, KB_##K29, KB_##K2A, KB_##K2B, KB_##K2C, KB_##K2D, KB_##K2E, KB_##K2F }, \ + { KB_##K30, KB_##K31, KB_##K32, KB_##K33, KB_##K34, KB_NO, KB_NO, KB_##K37 }, \ + { KB_##K38, KB_##K39, KB_##K3A, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO } \ +} + + +// Assign Fn key(0-7) to a layer to which switch with the Fn key pressed. +static const uint8_t PROGMEM fn_layer[] = { + 0, // Fn0 + 0, // Fn1 + 0, // Fn2 + 0, // Fn3 + 0, // Fn4 + 0, // Fn5 + 0, // Fn6 + 0 // Fn7 +}; + +// Assign Fn key(0-7) to a keycode sent when release Fn key without use of the layer. +// See layer.c for details. +static const uint8_t PROGMEM fn_keycode[] = { + KB_NO, // Fn0 + KB_NO, // Fn1 + KB_NO, // Fn2 + KB_NO, // Fn3 + KB_NO, // Fn4 + KB_NO, // Fn5 + KB_NO, // Fn6 + KB_NO // Fn7 +}; + +static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + /* Default Layer: plain keymap + * ,---------------------------------------------------------. + * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Bacpa| + * |---------------------------------------------------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| + * |---------------------------------------------------------| + * |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return| + * |---------------------------------------------------------| + * |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shift | + * `---------------------------------------------------------' + * |Opt|Alt | Space |Alt |Opt| + * `-----------------------------------------------' + */ + KEYMAP( + GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, + CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, + LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, + LGUI,LALT, SPC, RALT + ), +}; + + +uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col) +{ + return KEYCODE(layer, row, col); +} + +uint8_t keymap_fn_layer(uint8_t fn_bits) +{ + return pgm_read_byte(&fn_layer[biton(fn_bits)]); +} + +uint8_t keymap_fn_keycode(uint8_t fn_bits) +{ + return pgm_read_byte(&fn_keycode[(biton(fn_bits))]); +} diff --git a/m0110_usb/led.c b/m0110_usb/led.c new file mode 100644 index 000000000..f76545f0b --- /dev/null +++ b/m0110_usb/led.c @@ -0,0 +1,24 @@ +/* +Copyright 2011 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "stdint.h" +#include "led.h" + + +void led_set(uint8_t usb_led) +{ +} diff --git a/m0110_usb/matrix.c b/m0110_usb/matrix.c new file mode 100644 index 000000000..f045920cc --- /dev/null +++ b/m0110_usb/matrix.c @@ -0,0 +1,193 @@ +/* +Copyright 2011 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * scan matrix + */ +#include <stdint.h> +#include <stdbool.h> +#include <avr/io.h> +#include <util/delay.h> +#include "print.h" +#include "util.h" +#include "debug.h" +#include "host.h" +#include "led.h" +#include "m0110.h" +#include "matrix.h" + + +#define CAPS 0x39 +#define CAPS_UP (CAPS | 0x80) +#define ROW(key) ((key)>>3&0x0F) +#define COL(key) ((key)&0x07) + + +static bool is_modified = false; + +// matrix state buffer(1:on, 0:off) +static uint8_t *matrix; +static uint8_t _matrix0[MATRIX_ROWS]; + +#ifdef MATRIX_HAS_GHOST +static bool matrix_has_ghost_in_row(uint8_t row); +#endif +static void register_key(uint8_t key); + + +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +void matrix_init(void) +{ + print_enable = true; + debug_enable = true; + debug_matrix = false; + debug_keyboard = false; + debug_mouse = false; + print("debug enabled.\n"); + + m0110_init(); + // initialize matrix state: all keys off + for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00; + matrix = _matrix0; + return; +} + +uint8_t matrix_scan(void) +{ + uint8_t key; + + is_modified = false; + key = m0110_recv_key(); + +#ifdef MATRIX_HAS_LOCKING_CAPS + // Send Caps key up event + if (matrix_is_on(ROW(CAPS), COL(CAPS))) { + is_modified = true; + register_key(CAPS_UP); + } +#endif + if (key == M0110_NULL) { + return 0; + } else { +#ifdef MATRIX_HAS_LOCKING_CAPS + if (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) { + // CAPS LOCK on: + // Ignore LockingCaps key down event + if (key == CAPS) return 0; + // Convert LockingCaps key up event into down event + if (key == CAPS_UP) key = CAPS; + } else { + // CAPS LOCK off: + // Ignore LockingCaps key up event + if (key == CAPS_UP) return 0; + } +#endif + is_modified = true; + register_key(key); + } + + if (debug_enable) { + print("key: "); phex(key); print("\n"); + } + return 1; +} + +bool matrix_is_modified(void) +{ + return is_modified; +} + +inline +bool matrix_has_ghost(void) +{ +#ifdef MATRIX_HAS_GHOST + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + if (matrix_has_ghost_in_row(i)) + return true; + } +#endif + return false; +} + +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & (1<<col)); +} + +inline +uint8_t matrix_get_row(uint8_t row) +{ + return matrix[row]; +} + +void matrix_print(void) +{ + print("\nr/c 01234567\n"); + for (uint8_t row = 0; row < matrix_rows(); row++) { + phex(row); print(": "); + pbin_reverse(matrix_get_row(row)); + print("\n"); + } +} + +uint8_t matrix_key_count(void) +{ + uint8_t count = 0; + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + count += bitpop(matrix[i]); + } + return count; +} + +#ifdef MATRIX_HAS_GHOST +inline +static bool matrix_has_ghost_in_row(uint8_t row) +{ + // no ghost exists in case less than 2 keys on + if (((matrix[row] - 1) & matrix[row]) == 0) + return false; + + // ghost exists in case same state as other row + for (uint8_t i=0; i < MATRIX_ROWS; i++) { + if (i != row && (matrix[i] & matrix[row]) == matrix[row]) + return true; + } + return false; +} +#endif + +inline +static void register_key(uint8_t key) +{ + if (key&0x80) { + matrix[ROW(key)] &= ~(1<<COL(key)); + } else { + matrix[ROW(key)] |= (1<<COL(key)); + } +} |