aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortmk <nobody@nowhere>2014-02-09 02:42:17 +0900
committertmk <nobody@nowhere>2014-02-09 02:42:17 +0900
commitebe951a445b5d774542731d6165a9c5cd56beb2b (patch)
treef907b82fa3cbeeea4dc8cea96f83ee0d298372d5
parentcb3a547ebff8e09401c7d635ed24585a7521bb19 (diff)
downloadqmk_firmware-ebe951a445b5d774542731d6165a9c5cd56beb2b.tar.gz
qmk_firmware-ebe951a445b5d774542731d6165a9c5cd56beb2b.zip
Add Initial files of 4704_usb
-rw-r--r--converter/ibm4704_usb/Makefile93
-rw-r--r--converter/ibm4704_usb/README.md31
-rw-r--r--converter/ibm4704_usb/config.h73
-rw-r--r--converter/ibm4704_usb/keymap_common.c30
-rw-r--r--converter/ibm4704_usb/keymap_common.h73
-rw-r--r--converter/ibm4704_usb/keymap_plain.c28
-rw-r--r--converter/ibm4704_usb/led.c24
-rw-r--r--converter/ibm4704_usb/matrix.c179
-rw-r--r--protocol/ibm4704.c150
-rw-r--r--protocol/ibm4704.h111
10 files changed, 792 insertions, 0 deletions
diff --git a/converter/ibm4704_usb/Makefile b/converter/ibm4704_usb/Makefile
new file mode 100644
index 000000000..bc0f9fde7
--- /dev/null
+++ b/converter/ibm4704_usb/Makefile
@@ -0,0 +1,93 @@
1# Target file name (without extension).
2TARGET = ibm4704_usb
3
4# Directory common source filess exist
5TOP_DIR = ../..
6
7# Directory keyboard dependent files exist
8TARGET_DIR = .
9
10# project specific files
11SRC = keymap_common.c \
12 matrix.c \
13 led.c \
14 protocol/ibm4704.c
15
16ifdef KEYMAP
17 SRC := keymap_$(KEYMAP).c $(SRC)
18else
19 SRC := keymap_plain.c $(SRC)
20endif
21
22CONFIG_H = config.h
23
24
25# MCU name
26#MCU = at90usb1287
27MCU = atmega32u4
28
29# Processor frequency.
30# This will define a symbol, F_CPU, in all source code files equal to the
31# processor frequency in Hz. You can then use this symbol in your source code to
32# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
33# automatically to create a 32-bit value in your source code.
34#
35# This will be an integer division of F_USB below, as it is sourced by
36# F_USB after it has run through any CPU prescalers. Note that this value
37# does not *change* the processor frequency - it should merely be updated to
38# reflect the processor speed set externally so that the code can use accurate
39# software delays.
40F_CPU = 16000000
41
42
43#
44# LUFA specific
45#
46# Target architecture (see library "Board Types" documentation).
47ARCH = AVR8
48
49# Input clock frequency.
50# This will define a symbol, F_USB, in all source code files equal to the
51# input clock frequency (before any prescaling is performed) in Hz. This value may
52# differ from F_CPU if prescaling is used on the latter, and is required as the
53# raw input clock is fed directly to the PLL sections of the AVR for high speed
54# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
55# at the end, this will be done automatically to create a 32-bit value in your
56# source code.
57#
58# If no clock division is performed on the input clock inside the AVR (via the
59# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
60F_USB = $(F_CPU)
61
62# Interrupt driven control endpoint task(+60)
63OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
64
65
66# Boot Section Size in *bytes*
67# Teensy halfKay 512
68# Teensy++ halfKay 1024
69# Atmel DFU loader 4096
70# LUFA bootloader 4096
71# USBaspLoader 2048
72OPT_DEFS += -DBOOTLOADER_SIZE=4096
73
74
75# Build Options
76# comment out to disable the options.
77#
78#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
79#MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
80##EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
81CONSOLE_ENABLE = yes # Console for debug(+400)
82COMMAND_ENABLE = yes # Commands for debug and configuration
83#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA
84
85
86# Search Path
87VPATH += $(TARGET_DIR)
88VPATH += $(TOP_DIR)
89
90include $(TOP_DIR)/protocol.mk
91include $(TOP_DIR)/protocol/lufa.mk
92include $(TOP_DIR)/common.mk
93include $(TOP_DIR)/rules.mk
diff --git a/converter/ibm4704_usb/README.md b/converter/ibm4704_usb/README.md
new file mode 100644
index 000000000..1e29945d0
--- /dev/null
+++ b/converter/ibm4704_usb/README.md
@@ -0,0 +1,31 @@
1IBM 4704 to USB keyboard converter
2=======----=======================
3This firmware converts IBM 4704 keyboard protocol to USB HID.
4
5
6Connect Wires
7-------------
8In case of Teensy2.0(ATMega32U4):
9
101. Connect Vcc and GND.
112. Connect Clock and Data line.
12 - Clock is on PD1 and Data on PD2.
133. Optionally you need pull-up register. 1KOhm is OK?
14
15To change pin configuration edit config.h.
16
17
18Build Firmware
19--------------
20Just run `make`:
21
22 $ make
23
24To select keymap:
25
26 $ make KEYMAP=[plain|...]
27
28
29Keymap
30------
31Several 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.
diff --git a/converter/ibm4704_usb/config.h b/converter/ibm4704_usb/config.h
new file mode 100644
index 000000000..8c2d08f6f
--- /dev/null
+++ b/converter/ibm4704_usb/config.h
@@ -0,0 +1,73 @@
1/*
2Copyright 2014 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#ifndef CONFIG_H
19#define CONFIG_H
20
21#include <avr/interrupt.h>
22
23#define VENDOR_ID 0xFEED
24#define PRODUCT_ID 0x4707
25#define DEVICE_VER 0x0001
26#define MANUFACTURER t.m.k.
27#define PRODUCT IBM 4704 keyboard converter
28#define DESCRIPTION convert IBM 4704 keyboard to USB
29
30
31/* matrix size */
32#define MATRIX_ROWS 16 // keycode bit3-6
33#define MATRIX_COLS 8 // keycode bit0-2
34
35
36/* key combination for command */
37#define IS_COMMAND() ( \
38 keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
39)
40
41
42
43/*
44 * Busywait
45 */
46#define IBM4704_CLOCK_PORT PORTD
47#define IBM4704_CLOCK_PIN PIND
48#define IBM4704_CLOCK_DDR DDRD
49#define IBM4704_CLOCK_BIT 1
50#define IBM4704_DATA_PORT PORTD
51#define IBM4704_DATA_PIN PIND
52#define IBM4704_DATA_DDR DDRD
53#define IBM4704_DATA_BIT 2
54
55/*
56 * Pin interrupt
57 */
58#ifdef IBM4704_USE_INT
59#define IBM4704_INT_INIT() do { \
60 EICRA |= ((1<<ISC11) | \
61 (0<<ISC10)); \
62} while (0)
63#define IBM4704_INT_ON() do { \
64 EIMSK |= (1<<INT1); \
65} while (0)
66#define IBM4704_INT_OFF() do { \
67 EIMSK &= ~(1<<INT1); \
68} while (0)
69#define IBM4704_INT_VECT INT1_vect
70#endif
71
72
73#endif
diff --git a/converter/ibm4704_usb/keymap_common.c b/converter/ibm4704_usb/keymap_common.c
new file mode 100644
index 000000000..241d2e33b
--- /dev/null
+++ b/converter/ibm4704_usb/keymap_common.c
@@ -0,0 +1,30 @@
1/*
2Copyright 2011,2012,2013 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include "keymap_common.h"
18
19
20/* translates key to keycode */
21uint8_t keymap_key_to_keycode(uint8_t layer, key_t key)
22{
23 return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]);
24}
25
26/* translates Fn keycode to action */
27action_t keymap_fn_to_action(uint8_t keycode)
28{
29 return (action_t){ .code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]) };
30}
diff --git a/converter/ibm4704_usb/keymap_common.h b/converter/ibm4704_usb/keymap_common.h
new file mode 100644
index 000000000..8955baeb5
--- /dev/null
+++ b/converter/ibm4704_usb/keymap_common.h
@@ -0,0 +1,73 @@
1/*
2Copyright 2011,2012,2013 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17#ifndef KEYMAP_COMMON_H
18#define KEYMAP_COMMON_H
19
20#include <stdint.h>
21#include <stdbool.h>
22#include <avr/pgmspace.h>
23#include "keycode.h"
24#include "action.h"
25#include "action_macro.h"
26#include "report.h"
27#include "print.h"
28#include "debug.h"
29#include "keymap.h"
30
31
32// 32*8(256) byte array which converts PS/2 code into USB code
33extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
34extern const uint16_t fn_actions[];
35
36
37/* Original keys */
38#define KEYMAP( \
39 K00,K18,K19,K1A,K10,K11,K12,K08,K09,K0A,K0F,K1F,K0D,K0C,K0E, \
40 K04,K05,K06,K13,K14,K15,K16,K17,K01,K02,K03,K1B,K1C,K1D, \
41 K20,K21,K22,K23,K24,K25,K26,K27,K28,K29,K2A,K2B,K2C,K2D, \
42 K30,K3E,K32,K33,K34,K35,K36,K37,K38,K39,K3A,K3B,K3D, \
43 K31,K41,K3F, K40, K42,K2F \
44) { \
45 { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_NO }, \
46 { KC_##K08, KC_##K09, KC_##K0A, KC_NO, KC_##K0C, KC_##K0D, KC_##K0E, KC_##K0F }, \
47 { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17 }, \
48 { KC_##K18, KC_##K19, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D, KC_NO, KC_##K1F }, \
49 { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27 }, \
50 { KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_NO, KC_##K2F }, \
51 { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37 }, \
52 { KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_NO, KC_##K3D, KC_##K3E, KC_##K3F }, \
53 { KC_##K40, KC_##K41, KC_##K42, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
54 { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
55 { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
56 { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
57 { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
58 { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
59 { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
60 { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \
61}
62
63#endif
64
65/*
66 { K48, K49, K4A, K4B, K4C, K4D, K4E, K4F }, \
67 { K50, K51, K52, K53, K54, K55, K56, K57 }, \
68 { K58, K59, K5A, K5B, K5C, K5D, K5E, K5F }, \
69 { K60, K61, K62, K63, K64, K65, K66, K67 }, \
70 { K68, K69, K6A, K6B, K6C, K6D, K6E, K6F }, \
71 { K70, K71, K72, K73, K74, K75, K76, K77 }, \
72 { K78, K79, K7A, K7B, K7C, K7D, K7E, K7F }, \
73*/
diff --git a/converter/ibm4704_usb/keymap_plain.c b/converter/ibm4704_usb/keymap_plain.c
new file mode 100644
index 000000000..0ca4f14c1
--- /dev/null
+++ b/converter/ibm4704_usb/keymap_plain.c
@@ -0,0 +1,28 @@
1#include "keymap_common.h"
2
3
4const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
5 /* 0: default
6 * ,-----------------------------------------------------------.
7 * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|???|BS |
8 * |-----------------------------------------------------------|
9 * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \|
10 * |-----------------------------------------------------------|
11 * |Ctrl | A| S| D| F| G| H| J| K| L| ;| '|???|Ret |
12 * |-----------------------------------------------------------|
13 * |Shif|???| Z| X| C| V| B| N| M| ,| ,| /|???|Shift |
14 * |-----------------------------------------------------------|
15 * |Ctrl |Gui|Alt | Space |Alt |Gui|Ctrl |
16 * `-----------------------------------------------------------'
17 */
18 KEYMAP(
19 ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSLS,GRV, \
20 TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSPC, \
21 LCTL,A, S, D, F, G, H, J, K, L, SCLN,QUOT,NO, ENT, \
22 LSFT,NO, Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, \
23 LCTL,LGUI,LALT, SPC, RGUI,RCTL \
24 ),
25};
26
27const uint16_t PROGMEM fn_actions[] = {
28};
diff --git a/converter/ibm4704_usb/led.c b/converter/ibm4704_usb/led.c
new file mode 100644
index 000000000..f76545f0b
--- /dev/null
+++ b/converter/ibm4704_usb/led.c
@@ -0,0 +1,24 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "stdint.h"
19#include "led.h"
20
21
22void led_set(uint8_t usb_led)
23{
24}
diff --git a/converter/ibm4704_usb/matrix.c b/converter/ibm4704_usb/matrix.c
new file mode 100644
index 000000000..796e2d064
--- /dev/null
+++ b/converter/ibm4704_usb/matrix.c
@@ -0,0 +1,179 @@
1/*
2Copyright 2014 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include <stdint.h>
19#include <stdbool.h>
20#include <avr/io.h>
21#include <util/delay.h>
22#include "action.h"
23#include "print.h"
24#include "debug.h"
25#include "util.h"
26#include "ibm4704.h"
27#include "matrix.h"
28
29
30static void matrix_make(uint8_t code);
31static void matrix_break(uint8_t code);
32static void matrix_clear(void);
33
34
35/*
36 * Matrix Array usage:
37 * IBM 4704 scan codes are assigned into 128(16x8)-cell matrix.
38 *
39 * 8bit wide
40 * +---------+
41 * 0| |
42 * :| XX | 00-7F
43 * f| |
44 * +---------+
45 *
46 * Exceptions:
47 */
48static uint8_t matrix[MATRIX_ROWS];
49
50// scan code bits 7654 3210
51// R:row/C:column -RRR RCCC
52#define ROW(code) ((code>>3)&0x0f)
53#define COL(code) (code&0x07)
54
55
56inline
57uint8_t matrix_rows(void)
58{
59 return MATRIX_ROWS;
60}
61
62inline
63uint8_t matrix_cols(void)
64{
65 return MATRIX_COLS;
66}
67
68static void enable_break(void)
69{
70 uint8_t ret;
71 for (uint8_t code = 0; code < 0x80; code++) {
72 while (ibm4704_send(0x80|code) != 0) {
73 print("z");
74 }
75 _delay_ms(1);
76 ret = ibm4704_recv();
77 if (ret!=0xFF) {
78 xprintf("%0X: %0X ", code, ret);
79 }
80 }
81 _delay_us(100);
82 print("End\n");
83 while (ibm4704_send(0xFF) != 0) {
84 print("Z");
85 } // End
86}
87
88void matrix_init(void)
89{
90 debug_enable = true;
91
92 ibm4704_init();
93 matrix_clear();
94
95 xprintf("------\n");
96 enable_break();
97 //while (ibm4704_send(0x8C) != 0) ;
98 //while (ibm4704_send(0xFF) != 0) ;
99}
100
101/*
102 * IBM 4704 Scan Code
103 */
104uint8_t matrix_scan(void)
105{
106 uint8_t code = ibm4704_recv();
107 if (code==0xFF) {
108 // Not receivd
109 return 0;
110 } else if ((code&0x78)==0x78) {
111 // 0xFF-F8 and 0x7F-78 is not scan code
112 dprintf("Error: %0X\n", code);
113 matrix_clear();
114 return 0;
115 } else if (code&0x80) {
116 matrix_make(code);
117 } else {
118 matrix_break(code);
119 }
120 return 1;
121}
122
123inline
124bool matrix_has_ghost(void)
125{
126 return false;
127}
128
129inline
130bool matrix_is_on(uint8_t row, uint8_t col)
131{
132 return (matrix[row] & (1<<col));
133}
134
135inline
136uint8_t matrix_get_row(uint8_t row)
137{
138 return matrix[row];
139}
140
141void matrix_print(void)
142{
143 print("\nr/c 01234567\n");
144 for (uint8_t row = 0; row < matrix_rows(); row++) {
145 // TODO: use new function
146 phex(row); print(": ");
147 pbin_reverse(matrix_get_row(row));
148 print("\n");
149 }
150}
151
152uint8_t matrix_key_count(void)
153{
154 uint8_t count = 0;
155 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
156 count += bitpop(matrix[i]);
157 }
158 return count;
159}
160
161
162
163inline
164static void matrix_make(uint8_t code)
165{
166 matrix[ROW(code)] |= 1<<COL(code);
167}
168
169inline
170static void matrix_break(uint8_t code)
171{
172 matrix[ROW(code)] &= ~(1<<COL(code));
173}
174
175inline
176static void matrix_clear(void)
177{
178 for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
179}
diff --git a/protocol/ibm4704.c b/protocol/ibm4704.c
new file mode 100644
index 000000000..26441ed52
--- /dev/null
+++ b/protocol/ibm4704.c
@@ -0,0 +1,150 @@
1/*
2Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
3*/
4#include <stdbool.h>
5#include <util/delay.h>
6#include "debug.h"
7#include "ibm4704.h"
8
9
10#define WAIT(stat, us, err) do { \
11 if (!wait_##stat(us)) { \
12 ibm4704_error = err; \
13 goto ERROR; \
14 } \
15} while (0)
16
17
18uint8_t ibm4704_error = 0;
19
20
21void ibm4704_init(void)
22{
23 // POR
24 //_delay_ms(2500);
25 //while ( 0xA3 != ibm4704_recv() ) ;
26
27 inhibit();
28 DDRD |= 1<<3;
29 PORTD &= ~(1<<3);
30}
31
32uint8_t ibm4704_send(uint8_t data)
33{
34 bool parity = true; // odd parity
35 ibm4704_error = 0;
36
37 /* Request to send */
38 idle();
39 clock_lo();
40PIND |= 1<<3;
41
42 /* wait for Start bit(Clock:lo/Data:hi) */
43 WAIT(data_hi, 300, 0x30);
44
45 /* Data bit */
46 for (uint8_t i = 0; i < 8; i++) {
47 WAIT(clock_hi, 100, 0x31);
48 //_delay_us(5);
49PIND |= 1<<3;
50 if (data&(1<<i)) {
51 parity = !parity;
52 data_hi();
53 } else {
54 data_lo();
55 }
56 WAIT(clock_lo, 100, 0x32);
57 }
58
59 /* Parity bit */
60 WAIT(clock_hi, 100, 4);
61PIND |= 1<<3;
62 if (parity) { data_hi(); } else { data_lo(); }
63 WAIT(clock_lo, 100, 5);
64
65 /* Stop bit */
66 WAIT(clock_hi, 100, 4);
67 data_hi();
68
69 /* End */
70 WAIT(data_lo, 100, 6);
71
72 inhibit();
73 _delay_us(200); // wait to recover clock to hi
74 return 0;
75ERROR:
76 inhibit();
77xprintf("x%02X ", ibm4704_error);
78 _delay_us(200); // wait to recover clock to hi
79 return -1;
80}
81
82/* receive data when host want else inhibit communication */
83uint8_t ibm4704_recv_response(void)
84{
85 // 250 * 100us(wait start bit in ibm4704_recv)
86 uint8_t data = 0;
87 uint8_t try = 250;
88 do {
89 data = ibm4704_recv();
90 } while (try-- && ibm4704_error);
91 return data;
92}
93
94/*
95Keyboard to Host:
96Clock ~~~~___~~_~~_~~_~~_~~_~~_~~_~~_~~_~~~~~~~~ H:60us/L:30us
97
98Data ____~~X==X==X==X==X==X==X==X==X==X________
99 | 0 1 2 3 4 5 6 7 P(odd)
100 | LSB MSB
101 Start bit(80us)
102*/
103uint8_t ibm4704_recv(void)
104{
105 uint8_t data = 0;
106 bool parity = true; // odd parity
107 ibm4704_error = IBM4704_ERR_NONE;
108
109 idle();
110 _delay_us(5); // wait for line settles
111
112 /* start bit */
113 WAIT(clock_lo, 100, 1); // wait for keyboard to send
114 WAIT(data_hi, 100, 2); // can be delayed that long
115
116 WAIT(clock_hi, 100, 3); // first rising edge which can take longer
117 /* data */
118 for (uint8_t i = 0; i < 8; i++) {
119 WAIT(clock_hi, 100, 0x20+i);
120 //_delay_us(5);
121 if (data_in()) {
122 parity = !parity;
123 data |= (1<<i);
124 }
125 WAIT(clock_lo, 150, 0x28+i);
126 }
127
128 /* parity */
129 WAIT(clock_hi, 100, 7);
130 if (data_in() != parity) {
131 ibm4704_error = IBM4704_ERR_PARITY;
132 goto ERROR;
133 }
134 WAIT(clock_lo, 150, 8);
135
136 /* stop bit */
137 WAIT(clock_hi, 100, 9);
138 WAIT(data_lo, 1, 9);
139
140 inhibit();
141 _delay_us(200); // wait to recover clock to hi
142 return data;
143ERROR:
144 if (ibm4704_error > 2) {
145 xprintf("x%02X ", ibm4704_error);
146 }
147 inhibit();
148 _delay_us(200); // wait to recover clock to hi
149 return -1;
150}
diff --git a/protocol/ibm4704.h b/protocol/ibm4704.h
new file mode 100644
index 000000000..ff8a5b771
--- /dev/null
+++ b/protocol/ibm4704.h
@@ -0,0 +1,111 @@
1/*
2Copyright 2014 Jun WAKO <wakojun@gmail.com>
3*/
4#ifndef IBM4704_H
5#define IBM4704_H
6
7#define IBM4704_ERR_NONE 0
8#define IBM4704_ERR_STARTBIT 1
9#define IBM4704_ERR_PARITY 0x70
10
11
12void ibm4704_init(void);
13uint8_t ibm4704_send(uint8_t data);
14uint8_t ibm4704_recv_response(void);
15uint8_t ibm4704_recv(void);
16
17
18/* Check pin configuration */
19#if !(defined(IBM4704_CLOCK_PORT) && \
20 defined(IBM4704_CLOCK_PIN) && \
21 defined(IBM4704_CLOCK_DDR) && \
22 defined(IBM4704_CLOCK_BIT))
23# error "ibm4704 clock pin configuration is required in config.h"
24#endif
25
26#if !(defined(IBM4704_DATA_PORT) && \
27 defined(IBM4704_DATA_PIN) && \
28 defined(IBM4704_DATA_DDR) && \
29 defined(IBM4704_DATA_BIT))
30# error "ibm4704 data pin configuration is required in config.h"
31#endif
32
33
34/*--------------------------------------------------------------------
35 * static functions
36 *------------------------------------------------------------------*/
37static inline void clock_lo(void)
38{
39 IBM4704_CLOCK_PORT &= ~(1<<IBM4704_CLOCK_BIT);
40 IBM4704_CLOCK_DDR |= (1<<IBM4704_CLOCK_BIT);
41}
42static inline void clock_hi(void)
43{
44 /* input with pull up */
45 IBM4704_CLOCK_DDR &= ~(1<<IBM4704_CLOCK_BIT);
46 IBM4704_CLOCK_PORT |= (1<<IBM4704_CLOCK_BIT);
47}
48static inline bool clock_in(void)
49{
50 IBM4704_CLOCK_DDR &= ~(1<<IBM4704_CLOCK_BIT);
51 IBM4704_CLOCK_PORT |= (1<<IBM4704_CLOCK_BIT);
52 _delay_us(1);
53 return IBM4704_CLOCK_PIN&(1<<IBM4704_CLOCK_BIT);
54}
55static inline void data_lo(void)
56{
57 IBM4704_DATA_PORT &= ~(1<<IBM4704_DATA_BIT);
58 IBM4704_DATA_DDR |= (1<<IBM4704_DATA_BIT);
59}
60static inline void data_hi(void)
61{
62 /* input with pull up */
63 IBM4704_DATA_DDR &= ~(1<<IBM4704_DATA_BIT);
64 IBM4704_DATA_PORT |= (1<<IBM4704_DATA_BIT);
65}
66static inline bool data_in(void)
67{
68 IBM4704_DATA_DDR &= ~(1<<IBM4704_DATA_BIT);
69 IBM4704_DATA_PORT |= (1<<IBM4704_DATA_BIT);
70 _delay_us(1);
71 return IBM4704_DATA_PIN&(1<<IBM4704_DATA_BIT);
72}
73
74static inline uint16_t wait_clock_lo(uint16_t us)
75{
76 while (clock_in() && us) { asm(""); _delay_us(1); us--; }
77 return us;
78}
79static inline uint16_t wait_clock_hi(uint16_t us)
80{
81 while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
82 return us;
83}
84static inline uint16_t wait_data_lo(uint16_t us)
85{
86 while (data_in() && us) { asm(""); _delay_us(1); us--; }
87 return us;
88}
89static inline uint16_t wait_data_hi(uint16_t us)
90{
91 while (!data_in() && us) { asm(""); _delay_us(1); us--; }
92 return us;
93}
94
95/* idle state that device can send */
96static inline void idle(void)
97{
98 clock_hi();
99 data_hi();
100}
101
102/* inhibit device to send
103 * keyboard checks Data line on start bit(Data:hi) and it stops sending if Data line is low.
104 */
105static inline void inhibit(void)
106{
107 clock_hi();
108 data_lo();
109}
110
111#endif