Merge branch 'ibm4704'
commit
188ab49dd3
|
@ -41,6 +41,7 @@ You can find some keyboard specific projects under `converter` and `keyboard` di
|
||||||
* [pc98_usb](converter/pc98_usb/) - [PC98] to USB
|
* [pc98_usb](converter/pc98_usb/) - [PC98] to USB
|
||||||
* [usb_usb](converter/usb_usb/) - USB to USB(experimental)
|
* [usb_usb](converter/usb_usb/) - USB to USB(experimental)
|
||||||
* [ascii_usb](converter/ascii_usb/) - ASCII(Serial console terminal) to USB
|
* [ascii_usb](converter/ascii_usb/) - ASCII(Serial console terminal) to USB
|
||||||
|
* [ibm4704_usb](converter/ibm4704_usb) - [IBM 4704 keyboard Converter][GH_ibm4704]
|
||||||
|
|
||||||
### keyboard
|
### keyboard
|
||||||
* [hhkb](keyboard/hhkb/) - [Happy Hacking Keyboard pro][GH_hhkb] **my main board**
|
* [hhkb](keyboard/hhkb/) - [Happy Hacking Keyboard pro][GH_hhkb] **my main board**
|
||||||
|
@ -62,6 +63,7 @@ You can find some keyboard specific projects under `converter` and `keyboard` di
|
||||||
[GH_terminal]: http://geekhack.org/showwiki.php?title=Island:27272
|
[GH_terminal]: http://geekhack.org/showwiki.php?title=Island:27272
|
||||||
[GH_x68k]: http://geekhack.org/showwiki.php?title=Island:29060
|
[GH_x68k]: http://geekhack.org/showwiki.php?title=Island:29060
|
||||||
[GH_hbkb]: http://geekhack.org/showwiki.php?title=Island:29483
|
[GH_hbkb]: http://geekhack.org/showwiki.php?title=Island:29483
|
||||||
|
[GH_ibm4704]: http://geekhack.org/index.php?topic=54706.0
|
||||||
[HID_liber]: http://deskthority.net/wiki/HID_Liberation_Device_-_DIY_Instructions
|
[HID_liber]: http://deskthority.net/wiki/HID_Liberation_Device_-_DIY_Instructions
|
||||||
[Phantom]: http://geekhack.org/index.php?topic=26742
|
[Phantom]: http://geekhack.org/index.php?topic=26742
|
||||||
[GH60]: http://geekhack.org/index.php?topic=34959
|
[GH60]: http://geekhack.org/index.php?topic=34959
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
# Target file name (without extension).
|
||||||
|
TARGET = ibm4704_usb
|
||||||
|
|
||||||
|
# Directory common source filess exist
|
||||||
|
TOP_DIR = ../..
|
||||||
|
|
||||||
|
# Directory keyboard dependent files exist
|
||||||
|
TARGET_DIR = .
|
||||||
|
|
||||||
|
# project specific files
|
||||||
|
SRC = keymap_common.c \
|
||||||
|
matrix.c \
|
||||||
|
led.c \
|
||||||
|
protocol/ibm4704.c
|
||||||
|
|
||||||
|
ifdef KEYMAP
|
||||||
|
SRC := keymap_$(KEYMAP).c $(SRC)
|
||||||
|
else
|
||||||
|
SRC := keymap_plain.c $(SRC)
|
||||||
|
endif
|
||||||
|
|
||||||
|
CONFIG_H = config.h
|
||||||
|
|
||||||
|
|
||||||
|
# MCU name
|
||||||
|
#MCU = at90usb1287
|
||||||
|
MCU = atmega32u4
|
||||||
|
|
||||||
|
# Processor frequency.
|
||||||
|
# This will define a symbol, F_CPU, in all source code files equal to the
|
||||||
|
# processor frequency in Hz. You can then use this symbol in your source code to
|
||||||
|
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
|
||||||
|
# automatically to create a 32-bit value in your source code.
|
||||||
|
#
|
||||||
|
# This will be an integer division of F_USB below, as it is sourced by
|
||||||
|
# F_USB after it has run through any CPU prescalers. Note that this value
|
||||||
|
# does not *change* the processor frequency - it should merely be updated to
|
||||||
|
# reflect the processor speed set externally so that the code can use accurate
|
||||||
|
# software delays.
|
||||||
|
F_CPU = 16000000
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# LUFA specific
|
||||||
|
#
|
||||||
|
# Target architecture (see library "Board Types" documentation).
|
||||||
|
ARCH = AVR8
|
||||||
|
|
||||||
|
# Input clock frequency.
|
||||||
|
# This will define a symbol, F_USB, in all source code files equal to the
|
||||||
|
# input clock frequency (before any prescaling is performed) in Hz. This value may
|
||||||
|
# differ from F_CPU if prescaling is used on the latter, and is required as the
|
||||||
|
# raw input clock is fed directly to the PLL sections of the AVR for high speed
|
||||||
|
# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
|
||||||
|
# at the end, this will be done automatically to create a 32-bit value in your
|
||||||
|
# source code.
|
||||||
|
#
|
||||||
|
# If no clock division is performed on the input clock inside the AVR (via the
|
||||||
|
# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
|
||||||
|
F_USB = $(F_CPU)
|
||||||
|
|
||||||
|
# Interrupt driven control endpoint task(+60)
|
||||||
|
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
|
||||||
|
|
||||||
|
|
||||||
|
# Boot Section Size in *bytes*
|
||||||
|
# Teensy halfKay 512
|
||||||
|
# Teensy++ halfKay 1024
|
||||||
|
# Atmel DFU loader 4096
|
||||||
|
# LUFA bootloader 4096
|
||||||
|
# USBaspLoader 2048
|
||||||
|
OPT_DEFS += -DBOOTLOADER_SIZE=4096
|
||||||
|
|
||||||
|
|
||||||
|
# Build Options
|
||||||
|
# comment out to disable the options.
|
||||||
|
#
|
||||||
|
#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
|
||||||
|
MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
|
||||||
|
EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
|
||||||
|
CONSOLE_ENABLE = yes # Console for debug(+400)
|
||||||
|
COMMAND_ENABLE = yes # Commands for debug and configuration
|
||||||
|
#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA
|
||||||
|
|
||||||
|
|
||||||
|
# Search Path
|
||||||
|
VPATH += $(TARGET_DIR)
|
||||||
|
VPATH += $(TOP_DIR)
|
||||||
|
|
||||||
|
include $(TOP_DIR)/protocol.mk
|
||||||
|
include $(TOP_DIR)/protocol/lufa.mk
|
||||||
|
include $(TOP_DIR)/common.mk
|
||||||
|
include $(TOP_DIR)/rules.mk
|
|
@ -0,0 +1,46 @@
|
||||||
|
IBM 4704 to USB keyboard converter
|
||||||
|
==================================
|
||||||
|
This firmware converts IBM 4704 keyboard protocol to USB HID.
|
||||||
|
|
||||||
|
Keyboard initialization process takes a few seconds at start up. During that you will hear buzzer from the keyboard. **You need to plug USB cable after hooking up your keyboard to the converter.**
|
||||||
|
|
||||||
|
|
||||||
|
4704 Connector
|
||||||
|
--------------
|
||||||
|
Keyboard Plug from front:
|
||||||
|
|
||||||
|
DSUB-9
|
||||||
|
-------------
|
||||||
|
\ N 2 3 4 5 /
|
||||||
|
\ N N N N /
|
||||||
|
---------
|
||||||
|
2 GND
|
||||||
|
3 VCC 5V
|
||||||
|
4 DATA
|
||||||
|
5 CLOCK
|
||||||
|
N No connection/No pin.
|
||||||
|
|
||||||
|
|
||||||
|
Connection
|
||||||
|
----------
|
||||||
|
In case of using ATMega32U4(Teensy2.0):
|
||||||
|
|
||||||
|
1. Supply power with VCC and GND.
|
||||||
|
2. Connect CLOCK to PD1 and DATA to PD0. You can change pin with config.h.
|
||||||
|
3. Optionally you may need pull-up register. 1KOhm probably work.
|
||||||
|
|
||||||
|
|
||||||
|
Build Firmware
|
||||||
|
--------------
|
||||||
|
Just run `make`:
|
||||||
|
|
||||||
|
$ make
|
||||||
|
|
||||||
|
To select keymap:
|
||||||
|
|
||||||
|
$ make KEYMAP=[plain|...]
|
||||||
|
|
||||||
|
|
||||||
|
Keymap
|
||||||
|
------
|
||||||
|
Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create file named `keymap_<name>.c` and see keymap document(you can find in top README.md) and existent keymap files.
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
Copyright 2014 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
|
||||||
|
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
|
#define VENDOR_ID 0xFEED
|
||||||
|
#define PRODUCT_ID 0x4707
|
||||||
|
#define DEVICE_VER 0x0001
|
||||||
|
#define MANUFACTURER t.m.k.
|
||||||
|
#define PRODUCT IBM 4704 keyboard converter
|
||||||
|
#define DESCRIPTION convert IBM 4704 keyboard to USB
|
||||||
|
|
||||||
|
|
||||||
|
/* matrix size */
|
||||||
|
#define MATRIX_ROWS 16 // keycode bit3-6
|
||||||
|
#define MATRIX_COLS 8 // keycode bit0-2
|
||||||
|
|
||||||
|
|
||||||
|
/* key combination for command */
|
||||||
|
#define IS_COMMAND() ( \
|
||||||
|
keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Busywait
|
||||||
|
*/
|
||||||
|
#define IBM4704_CLOCK_PORT PORTD
|
||||||
|
#define IBM4704_CLOCK_PIN PIND
|
||||||
|
#define IBM4704_CLOCK_DDR DDRD
|
||||||
|
#define IBM4704_CLOCK_BIT 1
|
||||||
|
#define IBM4704_DATA_PORT PORTD
|
||||||
|
#define IBM4704_DATA_PIN PIND
|
||||||
|
#define IBM4704_DATA_DDR DDRD
|
||||||
|
#define IBM4704_DATA_BIT 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pin interrupt
|
||||||
|
*/
|
||||||
|
#ifdef IBM4704_USE_INT
|
||||||
|
#define IBM4704_INT_INIT() do { \
|
||||||
|
EICRA |= ((1<<ISC11) | \
|
||||||
|
(0<<ISC10)); \
|
||||||
|
} while (0)
|
||||||
|
#define IBM4704_INT_ON() do { \
|
||||||
|
EIMSK |= (1<<INT1); \
|
||||||
|
} while (0)
|
||||||
|
#define IBM4704_INT_OFF() do { \
|
||||||
|
EIMSK &= ~(1<<INT1); \
|
||||||
|
} while (0)
|
||||||
|
#define IBM4704_INT_VECT INT1_vect
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,160 @@
|
||||||
|
4704 Keyboard
|
||||||
|
=============
|
||||||
|
Keyboard Models:
|
||||||
|
Model 100 6019273 50-key (grid layout)
|
||||||
|
Model 200 6019284 62-key Alpha(60% layout)
|
||||||
|
Model 300 6019303 77-key Expanded Alpha
|
||||||
|
Model 400 6020218 107-key Full key
|
||||||
|
|
||||||
|
Resourse
|
||||||
|
--------
|
||||||
|
The IBM 4704: lots of pictures and info
|
||||||
|
http://kishy.dyndns.org/?p=648#more-648
|
||||||
|
|
||||||
|
Brochure:
|
||||||
|
http://ed-thelen.org/comp-hist/IBM-ProdAnn/4700.pdf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
4704 Keyboard Protocol
|
||||||
|
======================
|
||||||
|
On powering up the keyboard sends keyboard id; A3h for 6019284(62-key), for example.
|
||||||
|
After that firmware enters FC command mode and waits for parameter data from host
|
||||||
|
so that it doesn't send any scancode until you send 'FF'(End of FC command).
|
||||||
|
|
||||||
|
|
||||||
|
Connector
|
||||||
|
---------
|
||||||
|
Keyboard Plug from front
|
||||||
|
|
||||||
|
DSUB-9
|
||||||
|
-------------
|
||||||
|
\ N 2 3 4 5 /
|
||||||
|
\ N N N N /
|
||||||
|
---------
|
||||||
|
2 GND
|
||||||
|
3 VCC 5V
|
||||||
|
4 DATA
|
||||||
|
5 CLOCK
|
||||||
|
N No connection/No pin.
|
||||||
|
|
||||||
|
|
||||||
|
Keyboard to Host
|
||||||
|
----------------
|
||||||
|
Data bits are LSB first and Pairty is odd. Clock has around 60us high and 30us low part.
|
||||||
|
|
||||||
|
____ __ __ __ __ __ __ __ __ __ ________
|
||||||
|
Clock \____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
|
||||||
|
____ ____ ____ ____ ____ ____ ____ ____ ____ ____
|
||||||
|
Data ____/ X____X____X____X____X____X____X____X____X____X________
|
||||||
|
Start 0 1 2 3 4 5 6 7 P Stop
|
||||||
|
|
||||||
|
Start bit: can be long as 300-350us.
|
||||||
|
Inhibit: Pull Data line down to inhibit keyboard to send.
|
||||||
|
Timing: Host reads bit while Clock is hi.
|
||||||
|
Stop bit: Keyboard pulls down Data line to lo after 9th clock.
|
||||||
|
|
||||||
|
|
||||||
|
Host to Keyboard
|
||||||
|
----------------
|
||||||
|
Data bits are LSB first and Pairty is odd. Clock has around 60us high and 30us low part.
|
||||||
|
|
||||||
|
____ __ __ __ __ __ __ __ __ __ ________
|
||||||
|
Clock \______/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
|
||||||
|
^ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___
|
||||||
|
Data ____|__/ X____X____X____X____X____X____X____X____X____X \___
|
||||||
|
| Start 0 1 2 3 4 5 6 7 P Stop
|
||||||
|
Request by host
|
||||||
|
|
||||||
|
Start bit: can be long as 300-350us.
|
||||||
|
Request: Host pulls Clock line down to request to send a command.
|
||||||
|
Timing: After Request keyboard pull up Data and down Clock line to low for start bit.
|
||||||
|
After request host release Clock line once Data line becomes hi.
|
||||||
|
Host wirtes a bit while Clock is hi and Keyboard reads while low.
|
||||||
|
Stop bit: Host releases or pulls up Data line to hi after 9th clock and waits for keybaord pull down the line to lo.
|
||||||
|
|
||||||
|
|
||||||
|
Scancodes
|
||||||
|
---------
|
||||||
|
Keyboard doesn't send Break code for all keys except for Alt by default.
|
||||||
|
|
||||||
|
6019284 62-key:
|
||||||
|
,-----------------------------------------------------------.
|
||||||
|
| `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|???|BS |
|
||||||
|
|-----------------------------------------------------------|
|
||||||
|
|Tab | Q| W| E| R| T| Y| U| I| O| P| ¢| \| PD2|
|
||||||
|
|-----------------------------------------------------------|
|
||||||
|
|Ctrl | A| S| D| F| G| H| J| K| L| ;| '| {}| PD3|
|
||||||
|
|-----------------------------------------------------------|
|
||||||
|
|Shif| <>| Z| X| C| V| B| N| M| ,| ,| /|???|Shift |
|
||||||
|
|-----------------------------------------------------------|
|
||||||
|
|Reset|blk|Alt | Space |Alt |blk|Enter|
|
||||||
|
`-----------------------------------------------------------'
|
||||||
|
+----------+---------------------+----------+----------+
|
||||||
|
|` 00|PD1 04|Caps 20|LShift 30|Reset 31|
|
||||||
|
|1 18|q 05|a 21|<> 3E|Rblank 41|
|
||||||
|
|2 19|w 06|s 22|z 32|Alt 3F|
|
||||||
|
|3 1A|e 13|d 23|x 33|Space 40|
|
||||||
|
|4 10|r 14|f 24|c 34|Alt 3F|
|
||||||
|
|5 11|t 15|g 25|v 35|Lblank 42|
|
||||||
|
|6 12|y 16|h 26|b 36|Enter 2F|
|
||||||
|
|7 08|u 17|j 27|n 37| |
|
||||||
|
|8 09|i 01|k 28|m 38| |
|
||||||
|
|9 0A|o 02|l 29|, 39| |
|
||||||
|
|0 0F|p 03|; 2A|. 3A| |
|
||||||
|
|- 1F|¢ 1B|' 2B|/ 3B| |
|
||||||
|
|= 0D|\ 1C|{} 2C|??? 3C| |
|
||||||
|
|??? 0C|PD2 1D|PD3 2D|RShift 3D| |
|
||||||
|
|BS 0E| | | | |
|
||||||
|
+----------+---------------------+----------+----------+
|
||||||
|
Bit7 is 'press flag' which set 1 on press and 0 on release when break code is enabled.
|
||||||
|
|
||||||
|
NOTE: When break code is enabled the key sends scancode with setting 7th bit on press
|
||||||
|
and without it on release. That is, '`' sends 80h on press and 00h on release.
|
||||||
|
|
||||||
|
|
||||||
|
keyboard command
|
||||||
|
----------------
|
||||||
|
FF Soft Reset(0008h)
|
||||||
|
FE Resend(00e8h)
|
||||||
|
FD Buzzer stop?(00edh)
|
||||||
|
FC Set Key flag(00f6h)
|
||||||
|
FB Soft Reset(0008h)
|
||||||
|
FA Reset(0000h)
|
||||||
|
|
||||||
|
|
||||||
|
Keyboard response
|
||||||
|
-----------------
|
||||||
|
FF Not exist. [Outgoing buffer cannot have FFh(00h in fact)]
|
||||||
|
FE Overflow(key event/receive data) at 00c5h, 0346h
|
||||||
|
FE Memory test error at 0224h
|
||||||
|
FD Command out of bound at 00d8h
|
||||||
|
Key out of bound
|
||||||
|
7E Read/Parity error in receive from host at 00bch
|
||||||
|
|
||||||
|
|
||||||
|
Set Key flag command(FC)
|
||||||
|
------------------------
|
||||||
|
After 'Power on Reset' firmware enters this command mode and waits for data from host,
|
||||||
|
so that you don't need to send 'FC' and it doesn't send any scancode until you send 'FF'.
|
||||||
|
|
||||||
|
Data sent from host:
|
||||||
|
|
||||||
|
bit: 7 6 ... 0
|
||||||
|
en | |
|
||||||
|
| `-----`--- scan code
|
||||||
|
`------------- enable bit(0: enable repeat, 1: enable break)
|
||||||
|
|
||||||
|
00-77 Enable repeat(78-7F: invalid scancode)
|
||||||
|
80-F7 Enable break(F8-FF: invalid scancode)
|
||||||
|
FE Resend(011ah) no need to use
|
||||||
|
FF End(0114h) exits FC command mode.
|
||||||
|
|
||||||
|
Response from keyboard:
|
||||||
|
FD Out of bound - Invalid scancode
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
To enable break code of all keys.
|
||||||
|
|
||||||
|
FC 80 81 ... F7 FF
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
Copyright 2011,2012,2013 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 "keymap_common.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* translates key to keycode */
|
||||||
|
uint8_t keymap_key_to_keycode(uint8_t layer, key_t key)
|
||||||
|
{
|
||||||
|
return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* translates Fn keycode to action */
|
||||||
|
action_t keymap_fn_to_action(uint8_t keycode)
|
||||||
|
{
|
||||||
|
return (action_t){ .code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]) };
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
Copyright 2011,2012,2013 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 KEYMAP_COMMON_H
|
||||||
|
#define KEYMAP_COMMON_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include "keycode.h"
|
||||||
|
#include "action.h"
|
||||||
|
#include "action_macro.h"
|
||||||
|
#include "report.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "keymap.h"
|
||||||
|
|
||||||
|
|
||||||
|
// 32*8(256) byte array which converts PS/2 code into USB code
|
||||||
|
extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
|
||||||
|
extern const uint16_t fn_actions[];
|
||||||
|
|
||||||
|
|
||||||
|
/* Original keys */
|
||||||
|
#define KEYMAP( \
|
||||||
|
K00,K18,K19,K1A,K10,K11,K12,K08,K09,K0A,K0F,K1F,K0D,K0C,K0E, \
|
||||||
|
K04,K05,K06,K13,K14,K15,K16,K17,K01,K02,K03,K1B,K1C,K1D, \
|
||||||
|
K20,K21,K22,K23,K24,K25,K26,K27,K28,K29,K2A,K2B,K2C,K2D, \
|
||||||
|
K30,K3E,K32,K33,K34,K35,K36,K37,K38,K39,K3A,K3B,K3C,K3D, \
|
||||||
|
K31,K41,K3F, K40, K42,K2F \
|
||||||
|
) { \
|
||||||
|
{ KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_NO }, \
|
||||||
|
{ KC_##K08, KC_##K09, KC_##K0A, KC_NO, KC_##K0C, KC_##K0D, KC_##K0E, KC_##K0F }, \
|
||||||
|
{ KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17 }, \
|
||||||
|
{ KC_##K18, KC_##K19, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D, KC_NO, KC_##K1F }, \
|
||||||
|
{ KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27 }, \
|
||||||
|
{ KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_NO, KC_##K2F }, \
|
||||||
|
{ KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37 }, \
|
||||||
|
{ KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D, KC_##K3E, KC_##K3F }, \
|
||||||
|
{ KC_##K40, KC_##K41, KC_##K42, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
|
||||||
|
{ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
|
||||||
|
{ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
|
||||||
|
{ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
|
||||||
|
{ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
|
||||||
|
{ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
|
||||||
|
{ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
|
||||||
|
{ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
{ K48, K49, K4A, K4B, K4C, K4D, K4E, K4F }, \
|
||||||
|
{ K50, K51, K52, K53, K54, K55, K56, K57 }, \
|
||||||
|
{ K58, K59, K5A, K5B, K5C, K5D, K5E, K5F }, \
|
||||||
|
{ K60, K61, K62, K63, K64, K65, K66, K67 }, \
|
||||||
|
{ K68, K69, K6A, K6B, K6C, K6D, K6E, K6F }, \
|
||||||
|
{ K70, K71, K72, K73, K74, K75, K76, K77 }, \
|
||||||
|
{ K78, K79, K7A, K7B, K7C, K7D, K7E, K7F }, \
|
||||||
|
*/
|
|
@ -0,0 +1,85 @@
|
||||||
|
#include "keymap_common.h"
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
|
/* 0: default
|
||||||
|
* ,-----------------------------------------------------------.
|
||||||
|
* | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|???|BS |
|
||||||
|
* |-----------------------------------------------------------|
|
||||||
|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \|
|
||||||
|
* |-----------------------------------------------------------|
|
||||||
|
* |Ctrl | A| S| D| F| G| H| J| K| L| ;| '|xxx|Ret |
|
||||||
|
* |-----------------------------------------------------------|
|
||||||
|
* |Shif|xxx| Z| X| C| V| B| N| M| ,| ,| /|xxx|Shift |
|
||||||
|
* |-----------------------------------------------------------|
|
||||||
|
* |Ctrl |Gui|Alt | Space |Alt |Gui|Ctrl |
|
||||||
|
* `-----------------------------------------------------------'
|
||||||
|
*/
|
||||||
|
KEYMAP(
|
||||||
|
ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSLS,GRV, \
|
||||||
|
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSPC, \
|
||||||
|
LCTL,A, S, D, F, G, H, J, K, L, FN1, QUOT,NO, ENT, \
|
||||||
|
LSFT,NO, Z, X, C, V, B, N, M, COMM,DOT, FN2, NO, FN0, \
|
||||||
|
LCTL,LGUI,LALT, FN3, RGUI,RCTL \
|
||||||
|
),
|
||||||
|
|
||||||
|
KEYMAP(
|
||||||
|
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \
|
||||||
|
CAPS,NO, NO, NO, NO, NO, NO, NO, PSCR,SLCK,PAUS, UP, NO, BSPC, \
|
||||||
|
LCTL,VOLD,VOLU,MUTE,NO, NO, PAST,PSLS,HOME,PGUP,LEFT,RGHT,NO, ENT, \
|
||||||
|
LSFT,NO, NO, NO, NO, NO, NO, PPLS,PMNS,END, PGDN,DOWN,NO, TRNS, \
|
||||||
|
LCTL,LGUI,LALT, SPC, RGUI,RCTL \
|
||||||
|
),
|
||||||
|
|
||||||
|
KEYMAP(
|
||||||
|
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \
|
||||||
|
TAB, NO, NO, NO, NO, NO, WH_L,WH_D,WH_U,WH_R,WSTP,WBAK,WFWD,BSPC, \
|
||||||
|
LCTL,NO, ACL0,ACL1,ACL2,NO, MS_L,MS_D,MS_U,MS_R,TRNS,NO, NO, ENT, \
|
||||||
|
LSFT,NO, NO, NO, NO, NO, BTN3,BTN2,BTN1,BTN4,BTN5,NO, NO, RSFT,\
|
||||||
|
LCTL,LGUI,LALT, BTN1, RGUI,RCTL \
|
||||||
|
),
|
||||||
|
|
||||||
|
KEYMAP(
|
||||||
|
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \
|
||||||
|
TAB, HOME,PGDN,UP, PGUP,END, HOME,PGDN,PGUP,END, NO, NO, NO, BSPC, \
|
||||||
|
LCTL,NO, LEFT,DOWN,RGHT,NO, LEFT,DOWN,UP, RGHT,NO, NO, NO, ENT, \
|
||||||
|
LSFT,NO, NO, NO, NO, NO, NO, HOME,PGDN,PGUP,END, TRNS,NO, RSFT, \
|
||||||
|
LCTL,LGUI,LALT, SPC, RGUI,RCTL \
|
||||||
|
),
|
||||||
|
|
||||||
|
KEYMAP(
|
||||||
|
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \
|
||||||
|
TAB, NO, NO, NO, NO, NO, WH_L,WH_D,MS_U,WH_U,WH_R,BTN4,BTN5,FN4, \
|
||||||
|
LCTL,VOLD,VOLU,MUTE,NO, NO, BTN2,MS_L,MS_D,MS_R,BTN1,NO, NO, ENT, \
|
||||||
|
LSFT,NO, NO, NO, NO, NO, BTN3,BTN2,BTN1,BTN4,BTN5,NO, NO, NO, \
|
||||||
|
LCTL,LGUI,LALT, TRNS, RGUI,RCTL \
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum macro_id {
|
||||||
|
ALT_TAB,
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16_t PROGMEM fn_actions[] = {
|
||||||
|
[0] = ACTION_LAYER_MOMENTARY(1),
|
||||||
|
[1] = ACTION_LAYER_TAP_KEY(2, KC_SCLN),
|
||||||
|
[2] = ACTION_LAYER_TAP_KEY(3, KC_SLASH),
|
||||||
|
[3] = ACTION_LAYER_TAP_KEY(4, KC_SPC),
|
||||||
|
[4] = ACTION_MACRO(ALT_TAB),
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macro definition
|
||||||
|
*/
|
||||||
|
const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
|
||||||
|
{
|
||||||
|
keyevent_t event = record->event;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case ALT_TAB:
|
||||||
|
return (event.pressed ?
|
||||||
|
MACRO( D(LALT), D(TAB), END ) :
|
||||||
|
MACRO( U(TAB), END ));
|
||||||
|
}
|
||||||
|
return MACRO_NONE;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
#include "keymap_common.h"
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
|
/* 0: default
|
||||||
|
* ,-----------------------------------------------------------.
|
||||||
|
* | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|???|BS |
|
||||||
|
* |-----------------------------------------------------------|
|
||||||
|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \|
|
||||||
|
* |-----------------------------------------------------------|
|
||||||
|
* |Ctrl | A| S| D| F| G| H| J| K| L| ;| '| #|Ret |
|
||||||
|
* |-----------------------------------------------------------|
|
||||||
|
* |Shif| \| Z| X| C| V| B| N| M| ,| ,| /|???|Shift |
|
||||||
|
* |-----------------------------------------------------------|
|
||||||
|
* |Ctrl |Gui|Alt | Space |Alt* |Gui|Ctrl |
|
||||||
|
* `-----------------------------------------------------------'
|
||||||
|
*/
|
||||||
|
KEYMAP(
|
||||||
|
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSLS,BSPC, \
|
||||||
|
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, \
|
||||||
|
LCTL,A, S, D, F, G, H, J, K, L, SCLN,QUOT,NUHS,ENT, \
|
||||||
|
LSFT,NUBS,Z, X, C, V, B, N, M, COMM,DOT, SLSH,NO, FN0, \
|
||||||
|
LCTL,LGUI,LALT, SPC, RGUI,RCTL \
|
||||||
|
),
|
||||||
|
|
||||||
|
/* 1: HHKB */
|
||||||
|
KEYMAP(
|
||||||
|
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \
|
||||||
|
CAPS,NO, NO, NO, NO, NO, NO, NO, PSCR,SLCK,PAUS, UP, NO, INS, \
|
||||||
|
LCTL,VOLD,VOLU,MUTE,NO, NO, PAST,PSLS,HOME,PGUP,LEFT,RGHT,NO, ENT, \
|
||||||
|
LSFT,NO, NO, NO, NO, NO, NO, PPLS,PMNS,END, PGDN,DOWN,NO, TRNS, \
|
||||||
|
LCTL,LGUI,LALT, SPC, RGUI,RCTL \
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16_t PROGMEM fn_actions[] = {
|
||||||
|
[0] = ACTION_LAYER_MOMENTARY(1),
|
||||||
|
};
|
|
@ -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)
|
||||||
|
{
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
Copyright 2014 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 <stdbool.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "action.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "ibm4704.h"
|
||||||
|
#include "matrix.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void matrix_make(uint8_t code);
|
||||||
|
static void matrix_break(uint8_t code);
|
||||||
|
static void matrix_clear(void);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Matrix Array usage:
|
||||||
|
* IBM 4704 scan codes are assigned into 128(16x8)-cell matrix.
|
||||||
|
*
|
||||||
|
* 8bit wide
|
||||||
|
* +---------+
|
||||||
|
* 0| |
|
||||||
|
* :| XX | 00-7F
|
||||||
|
* f| |
|
||||||
|
* +---------+
|
||||||
|
*
|
||||||
|
* Exceptions:
|
||||||
|
*/
|
||||||
|
static uint8_t matrix[MATRIX_ROWS];
|
||||||
|
|
||||||
|
// scan code bits 7654 3210
|
||||||
|
// R:row/C:column -RRR RCCC
|
||||||
|
#define ROW(code) ((code>>3)&0x0f)
|
||||||
|
#define COL(code) (code&0x07)
|
||||||
|
|
||||||
|
|
||||||
|
inline
|
||||||
|
uint8_t matrix_rows(void)
|
||||||
|
{
|
||||||
|
return MATRIX_ROWS;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
uint8_t matrix_cols(void)
|
||||||
|
{
|
||||||
|
return MATRIX_COLS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enable_break(void)
|
||||||
|
{
|
||||||
|
uint8_t ret;
|
||||||
|
print("Enable break: ");
|
||||||
|
// valid scancode: 00-77h
|
||||||
|
for (uint8_t code = 0; code < 0x78; code++) {
|
||||||
|
while (ibm4704_send(0x80|code) != 0) {
|
||||||
|
print("z");
|
||||||
|
_delay_us(500);
|
||||||
|
}
|
||||||
|
_delay_us(2000);
|
||||||
|
ret = ibm4704_recv();
|
||||||
|
if (ret != 0xff) {
|
||||||
|
xprintf("c%02X:r%02X ", code, ret);
|
||||||
|
}
|
||||||
|
_delay_us(1000);
|
||||||
|
}
|
||||||
|
_delay_us(1000);
|
||||||
|
while (ibm4704_send(0xFF) != 0) { _delay_us(500); } // End
|
||||||
|
print("End\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void matrix_init(void)
|
||||||
|
{
|
||||||
|
uint8_t ret;
|
||||||
|
debug_enable = true;
|
||||||
|
|
||||||
|
ibm4704_init();
|
||||||
|
matrix_clear();
|
||||||
|
|
||||||
|
// read keyboard id
|
||||||
|
while ((ret = ibm4704_recv()) == 0xFF) {
|
||||||
|
ibm4704_send(0xFE);
|
||||||
|
_delay_us(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
_delay_ms(2000); // wait for starting up debug console
|
||||||
|
print("IBM 4704 converter\n");
|
||||||
|
xprintf("Keyboard ID: %02X\n", ret);
|
||||||
|
enable_break();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IBM 4704 Scan Code
|
||||||
|
*/
|
||||||
|
uint8_t matrix_scan(void)
|
||||||
|
{
|
||||||
|
uint8_t code = ibm4704_recv();
|
||||||
|
if (code==0xFF) {
|
||||||
|
// Not receivd
|
||||||
|
return 0;
|
||||||
|
} else if ((code&0x78)==0x78) {
|
||||||
|
// 0xFF-F8 and 0x7F-78 is not scancode
|
||||||
|
xprintf("Error: %0X\n", code);
|
||||||
|
matrix_clear();
|
||||||
|
return 0;
|
||||||
|
} else if (code&0x80) {
|
||||||
|
matrix_make(code);
|
||||||
|
} else {
|
||||||
|
matrix_break(code);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
xprintf("%02X: %08b\n", row, bitrev(matrix_get_row(row)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline
|
||||||
|
static void matrix_make(uint8_t code)
|
||||||
|
{
|
||||||
|
matrix[ROW(code)] |= 1<<COL(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
static void matrix_break(uint8_t code)
|
||||||
|
{
|
||||||
|
matrix[ROW(code)] &= ~(1<<COL(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
static void matrix_clear(void)
|
||||||
|
{
|
||||||
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
|
||||||
|
}
|
|
@ -0,0 +1,169 @@
|
||||||
|
/*
|
||||||
|
Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
|
||||||
|
*/
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "debug.h"
|
||||||
|
#include "ibm4704.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define WAIT(stat, us, err) do { \
|
||||||
|
if (!wait_##stat(us)) { \
|
||||||
|
ibm4704_error = err; \
|
||||||
|
goto ERROR; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t ibm4704_error = 0;
|
||||||
|
|
||||||
|
|
||||||
|
void ibm4704_init(void)
|
||||||
|
{
|
||||||
|
inhibit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Host to Keyboard
|
||||||
|
----------------
|
||||||
|
Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
|
||||||
|
|
||||||
|
____ __ __ __ __ __ __ __ __ __ ________
|
||||||
|
Clock \______/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
|
||||||
|
^ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___
|
||||||
|
Data ____|__/ X____X____X____X____X____X____X____X____X____X \___
|
||||||
|
| Start 0 1 2 3 4 5 6 7 P Stop
|
||||||
|
Request by host
|
||||||
|
|
||||||
|
Start bit: can be long as 300-350us.
|
||||||
|
Request: Host pulls Clock line down to request to send a command.
|
||||||
|
Timing: After Request keyboard pull up Data and down Clock line to low for start bit.
|
||||||
|
After request host release Clock line once Data line becomes hi.
|
||||||
|
Host writes a bit while Clock is hi and Keyboard reads while low.
|
||||||
|
Stop bit: Host releases or pulls up Data line to hi after 9th clock and waits for keyboard pull down the line to lo.
|
||||||
|
*/
|
||||||
|
uint8_t ibm4704_send(uint8_t data)
|
||||||
|
{
|
||||||
|
bool parity = true; // odd parity
|
||||||
|
ibm4704_error = 0;
|
||||||
|
|
||||||
|
/* Request to send */
|
||||||
|
idle();
|
||||||
|
clock_lo();
|
||||||
|
|
||||||
|
/* wait for Start bit(Clock:lo/Data:hi) */
|
||||||
|
WAIT(data_hi, 300, 0x30);
|
||||||
|
|
||||||
|
/* Data bit */
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
WAIT(clock_hi, 100, 0x40+i);
|
||||||
|
//_delay_us(5);
|
||||||
|
if (data&(1<<i)) {
|
||||||
|
parity = !parity;
|
||||||
|
data_hi();
|
||||||
|
} else {
|
||||||
|
data_lo();
|
||||||
|
}
|
||||||
|
WAIT(clock_lo, 100, 0x48+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parity bit */
|
||||||
|
WAIT(clock_hi, 100, 0x34);
|
||||||
|
if (parity) { data_hi(); } else { data_lo(); }
|
||||||
|
WAIT(clock_lo, 100, 0x35);
|
||||||
|
|
||||||
|
/* Stop bit */
|
||||||
|
WAIT(clock_hi, 100, 0x34);
|
||||||
|
data_hi();
|
||||||
|
|
||||||
|
/* End */
|
||||||
|
WAIT(data_lo, 100, 0x36);
|
||||||
|
|
||||||
|
inhibit();
|
||||||
|
_delay_us(200); // wait to recover clock to hi
|
||||||
|
return 0;
|
||||||
|
ERROR:
|
||||||
|
inhibit();
|
||||||
|
if (ibm4704_error >= 0x30) {
|
||||||
|
xprintf("x%02X ", ibm4704_error);
|
||||||
|
}
|
||||||
|
_delay_us(200); // wait to recover clock to hi
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* receive data when host want else inhibit communication */
|
||||||
|
uint8_t ibm4704_recv_response(void)
|
||||||
|
{
|
||||||
|
// 250 * 100us(wait start bit in ibm4704_recv)
|
||||||
|
uint8_t data = 0;
|
||||||
|
uint8_t try = 250;
|
||||||
|
do {
|
||||||
|
data = ibm4704_recv();
|
||||||
|
} while (try-- && ibm4704_error);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Keyboard to Host
|
||||||
|
----------------
|
||||||
|
Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
|
||||||
|
|
||||||
|
____ __ __ __ __ __ __ __ __ __ ________
|
||||||
|
Clock \____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
|
||||||
|
____ ____ ____ ____ ____ ____ ____ ____ ____ ____
|
||||||
|
Data ____/ X____X____X____X____X____X____X____X____X____X________
|
||||||
|
Start 0 1 2 3 4 5 6 7 P Stop
|
||||||
|
|
||||||
|
Start bit: can be long as 300-350us.
|
||||||
|
Inhibit: Pull Data line down to inhibit keyboard to send.
|
||||||
|
Timing: Host reads bit while Clock is hi.
|
||||||
|
Stop bit: Keyboard pulls down Data line to lo after 9th clock.
|
||||||
|
*/
|
||||||
|
uint8_t ibm4704_recv(void)
|
||||||
|
{
|
||||||
|
uint8_t data = 0;
|
||||||
|
bool parity = true; // odd parity
|
||||||
|
ibm4704_error = IBM4704_ERR_NONE;
|
||||||
|
|
||||||
|
idle();
|
||||||
|
_delay_us(5); // wait for line settles
|
||||||
|
|
||||||
|
/* start bit */
|
||||||
|
WAIT(clock_lo, 100, 0x11); // wait for keyboard to send
|
||||||
|
WAIT(data_hi, 100, 0x12); // can be delayed that long
|
||||||
|
|
||||||
|
WAIT(clock_hi, 100, 0x13); // first rising edge which can take longer
|
||||||
|
/* data */
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
WAIT(clock_hi, 100, 0x20+i);
|
||||||
|
//_delay_us(5);
|
||||||
|
if (data_in()) {
|
||||||
|
parity = !parity;
|
||||||
|
data |= (1<<i);
|
||||||
|
}
|
||||||
|
WAIT(clock_lo, 150, 0x28+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parity */
|
||||||
|
WAIT(clock_hi, 100, 0x17);
|
||||||
|
if (data_in() != parity) {
|
||||||
|
ibm4704_error = IBM4704_ERR_PARITY;
|
||||||
|
goto ERROR;
|
||||||
|
}
|
||||||
|
WAIT(clock_lo, 150, 0x18);
|
||||||
|
|
||||||
|
/* stop bit */
|
||||||
|
WAIT(clock_hi, 100, 0x19);
|
||||||
|
WAIT(data_lo, 1, 0x19);
|
||||||
|
|
||||||
|
inhibit();
|
||||||
|
_delay_us(200); // wait to recover clock to hi
|
||||||
|
return data;
|
||||||
|
ERROR:
|
||||||
|
if (ibm4704_error > 0x12) {
|
||||||
|
xprintf("x%02X ", ibm4704_error);
|
||||||
|
}
|
||||||
|
inhibit();
|
||||||
|
_delay_us(200); // wait to recover clock to hi
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
Copyright 2014 Jun WAKO <wakojun@gmail.com>
|
||||||
|
*/
|
||||||
|
#ifndef IBM4704_H
|
||||||
|
#define IBM4704_H
|
||||||
|
|
||||||
|
#define IBM4704_ERR_NONE 0
|
||||||
|
#define IBM4704_ERR_PARITY 0x70
|
||||||
|
|
||||||
|
|
||||||
|
void ibm4704_init(void);
|
||||||
|
uint8_t ibm4704_send(uint8_t data);
|
||||||
|
uint8_t ibm4704_recv_response(void);
|
||||||
|
uint8_t ibm4704_recv(void);
|
||||||
|
|
||||||
|
|
||||||
|
/* Check pin configuration */
|
||||||
|
#if !(defined(IBM4704_CLOCK_PORT) && \
|
||||||
|
defined(IBM4704_CLOCK_PIN) && \
|
||||||
|
defined(IBM4704_CLOCK_DDR) && \
|
||||||
|
defined(IBM4704_CLOCK_BIT))
|
||||||
|
# error "ibm4704 clock pin configuration is required in config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !(defined(IBM4704_DATA_PORT) && \
|
||||||
|
defined(IBM4704_DATA_PIN) && \
|
||||||
|
defined(IBM4704_DATA_DDR) && \
|
||||||
|
defined(IBM4704_DATA_BIT))
|
||||||
|
# error "ibm4704 data pin configuration is required in config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------
|
||||||
|
* static functions
|
||||||
|
*------------------------------------------------------------------*/
|
||||||
|
static inline void clock_lo(void)
|
||||||
|
{
|
||||||
|
IBM4704_CLOCK_PORT &= ~(1<<IBM4704_CLOCK_BIT);
|
||||||
|
IBM4704_CLOCK_DDR |= (1<<IBM4704_CLOCK_BIT);
|
||||||
|
}
|
||||||
|
static inline void clock_hi(void)
|
||||||
|
{
|
||||||
|
/* input with pull up */
|
||||||
|
IBM4704_CLOCK_DDR &= ~(1<<IBM4704_CLOCK_BIT);
|
||||||
|
IBM4704_CLOCK_PORT |= (1<<IBM4704_CLOCK_BIT);
|
||||||
|
}
|
||||||
|
static inline bool clock_in(void)
|
||||||
|
{
|
||||||
|
IBM4704_CLOCK_DDR &= ~(1<<IBM4704_CLOCK_BIT);
|
||||||
|
IBM4704_CLOCK_PORT |= (1<<IBM4704_CLOCK_BIT);
|
||||||
|
_delay_us(1);
|
||||||
|
return IBM4704_CLOCK_PIN&(1<<IBM4704_CLOCK_BIT);
|
||||||
|
}
|
||||||
|
static inline void data_lo(void)
|
||||||
|
{
|
||||||
|
IBM4704_DATA_PORT &= ~(1<<IBM4704_DATA_BIT);
|
||||||
|
IBM4704_DATA_DDR |= (1<<IBM4704_DATA_BIT);
|
||||||
|
}
|
||||||
|
static inline void data_hi(void)
|
||||||
|
{
|
||||||
|
/* input with pull up */
|
||||||
|
IBM4704_DATA_DDR &= ~(1<<IBM4704_DATA_BIT);
|
||||||
|
IBM4704_DATA_PORT |= (1<<IBM4704_DATA_BIT);
|
||||||
|
}
|
||||||
|
static inline bool data_in(void)
|
||||||
|
{
|
||||||
|
IBM4704_DATA_DDR &= ~(1<<IBM4704_DATA_BIT);
|
||||||
|
IBM4704_DATA_PORT |= (1<<IBM4704_DATA_BIT);
|
||||||
|
_delay_us(1);
|
||||||
|
return IBM4704_DATA_PIN&(1<<IBM4704_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* idle state that device can send */
|
||||||
|
static inline void idle(void)
|
||||||
|
{
|
||||||
|
clock_hi();
|
||||||
|
data_hi();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inhibit device to send
|
||||||
|
* keyboard checks Data line on start bit(Data:hi) and it stops sending if Data line is low.
|
||||||
|
*/
|
||||||
|
static inline void inhibit(void)
|
||||||
|
{
|
||||||
|
clock_hi();
|
||||||
|
data_lo();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue