├── SunType5.jpg ├── LICENSE ├── scancodes-table.txt ├── SunKeyboard-to-USB ├── SunKeyboard-to-USB.ino └── sun_keyboard_map.h ├── SunKeyboard-Test └── SunKeyboard-Test.ino └── README.md /SunType5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benr/SunType5_ArduinoAdapter/HEAD/SunType5.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ben Rockwood 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /scancodes-table.txt: -------------------------------------------------------------------------------- 1 | #Ascii Sun Meaning 2 | 177 29 Esc 3 | 49 30 1 4 | 50 31 2 5 | 51 32 3 6 | 52 33 4 7 | 53 34 5 8 | 54 35 6 9 | 55 36 7 10 | 56 37 8 11 | 57 38 9 12 | 48 39 0 13 | 45 40 minus 14 | 61 41 equal 15 | 178 43 BackSpace 16 | 179 53 Tab 17 | 113 54 Q 18 | 119 55 W 19 | 101 56 E 20 | 114 57 R 21 | 116 58 T 22 | 121 59 Y 23 | 117 60 U 24 | 105 61 I 25 | 111 62 O 26 | 112 63 P 27 | 91 64 [ 28 | 93 65 ] 29 | 176 89 Return 30 | 128 76 Ctrl_L 31 | 97 77 A 32 | 115 78 S 33 | 100 79 D 34 | 102 80 F 35 | 103 81 G 36 | 104 82 H 37 | 106 83 J 38 | 107 84 K 39 | 108 85 L 40 | 59 86 ; 41 | 39 87 apostr. 42 | 126 42 grave/tilde 43 | 129 99 Shift_L 44 | 92 88 backslash 45 | 122 100 Z 46 | 120 101 X 47 | 99 102 C 48 | 118 103 V 49 | 98 104 B 50 | 110 105 N 51 | 109 106 M 52 | 44 107 , 53 | 46 108 . 54 | 47 109 / 55 | 133 110 Shift_R 56 | 42 47 R6/KP_Mult 57 | 131 120 Meta_L 58 | 32 121 SpaceBar 59 | 193 119 CapsLock 60 | 194 5 F1 61 | 195 6 F2 62 | 196 8 F3 63 | 197 10 F4 64 | 198 12 F5 65 | 199 14 F6 66 | 200 16 F7 67 | 201 17 F8 68 | 202 18 F9 69 | 203 7 F10 70 | 0 98 Num_Lock 71 | 210 68 R7/KP_7/Home 72 | 218 69 R8/KP_8/Up 73 | 211 70 R9/KP_9/PgUp 74 | 45 71 KP_Minus 75 | 52 91 R10/KP_4/Left 76 | 53 92 R11/KP_5/Center 77 | 54 93 R12/KP_6/Right 78 | 43 125 KP_Add 79 | 49 112 R13/KP_1/End 80 | 50 113 R14/KP_2/Down 81 | 51 114 R15/KP_3/PgDn 82 | 48 94 KP_0/KP_Insert 83 | 46 50 KP_./KP_Delete 84 | 204 9 F11 85 | 205 11 F12 86 | 0 22 Print_Screen 87 | 0 23 Scroll_Lock 88 | 0 21 Pause/Break 89 | 176 90 KP_Enter 90 | 128 76 Ctrl_L 91 | 47 46 R5/KP_Div 92 | 135 122 Meta_R 93 | 210 52 T5_Home 94 | 218 20 T5_Up 95 | 211 96 T5_PgUp 96 | 216 24 T5_Left 97 | 215 28 T5_Right 98 | 213 74 T5_End 99 | 217 27 T5_Down 100 | 214 123 T5_PgDn 101 | 209 44 T5_Insert 102 | 212 66 Delete 103 | 130 19 Alt_L 104 | #######Sun Special Keys################### 105 | 0 118 Help 106 | 0 1 Stop 107 | 0 3 Again 108 | 0 25 Props 109 | 0 26 Undo 110 | 0 49 Front 111 | 0 51 Copy 112 | 0 72 Open 113 | 0 73 Paste 114 | 0 95 Find 115 | 0 97 Cut 116 | 0 45 Mute 117 | 0 2 Volume_Decr 118 | 0 4 Volume_Incr 119 | 0 48 Power 120 | 121 | -------------------------------------------------------------------------------- /SunKeyboard-to-USB/SunKeyboard-to-USB.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * USB Adapter for Sun Type 5 Keyboard 3 | * Ben Rockwood 1/1/17 4 | * 5 | * Developed on Arduino Micro 6 | * MiniDIN 8a Adapter P/N: MD-80PL100 7 | * Wiring: 8 | * Keyboard Pin 2 (White): GND 9 | * Keyboard Pin 8 (Red): +5V 10 | * Keyboard Pin 6 (Yellow): Arduino Pin D10 (Serial RX) 11 | * Keyboard Pin 5 (Green): Aruidno Pin D11 (Serial TX) 12 | */ 13 | 14 | #include 15 | #include 16 | #include "sun_keyboard_map.h" 17 | 18 | //Software serial for Sun KBD 19 | SoftwareSerial sunSerial(10, 11, true); 20 | 21 | boolean NUM_LOCK_ON = false; // led bitfield xxx1 (1) 22 | boolean CAPS_LOCK_ON = false; // led bitfield 1xxx (8) 23 | 24 | byte led_cmd[2] = { 0x0E, 0x01 }; // Used for sending the 2 byte commands to the keyboard 25 | 26 | void setup() { 27 | Serial.begin(1200); // Normal serial for Serial Monitor Debugging 28 | sunSerial.begin(1200); // Serial Connection to Sun Keyboard 29 | 30 | Keyboard.begin(); // Initialize USB Keyboard Interface 31 | 32 | sunSerial.write(led_cmd, 2); // Enable Number Lock by Default 33 | } 34 | 35 | 36 | void loop() { 37 | char c = sunSerial.read(); 38 | 39 | if (c != 0xFFFFFFFF) { 40 | switch(c) { 41 | case 45: sunSerial.write(CMD_DISABLE_CLICK); break; // Mute Key to Disable Click Sound 42 | case 2: sunSerial.write(CMD_ENABLE_CLICK); break; // Decr Vol Key to Enable Click Sound 43 | case 4: sunSerial.write(CMD_ENABLE_BELL); break; // Incr Vol to Enable Bell 44 | case 48: sunSerial.write(CMD_DISABLE_BELL); break; // Power Key to Disable Bell 45 | case 98: break; // Ignore NumLock 46 | case 119: if (!CAPS_LOCK_ON) { // Caps Lock Toggle 47 | CAPS_LOCK_ON = true; 48 | led_cmd[1] += 8; 49 | sunSerial.write(led_cmd, 2); 50 | } else { 51 | CAPS_LOCK_ON = false; 52 | led_cmd[1] -= 8; 53 | sunSerial.write(led_cmd, 2); 54 | } 55 | default: outputKey(c); break; 56 | } 57 | } 58 | } 59 | 60 | 61 | void outputKey(int key){ 62 | 63 | if (key < 0) { 64 | key += 128; 65 | Serial.print("Key Up: "); Serial.println(sun_to_ascii[key]); 66 | Keyboard.release(sun_to_ascii[key]); 67 | } else if (key == 127) { 68 | Serial.println("All Keys Released"); 69 | Keyboard.releaseAll(); 70 | } else { 71 | Serial.print("Key Down: "); Serial.println(sun_to_ascii[key]); 72 | Keyboard.press(sun_to_ascii[key]); 73 | } 74 | } 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /SunKeyboard-to-USB/sun_keyboard_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | Keymap for Sun Keyboard to ASCII 3 | Fields are: 4 | Sun_KeyCode ASCII_Code Description 5 | */ 6 | 7 | #define CMD_RESET 0x01 8 | #define CMD_DISABLE_CLICK 0x0B 9 | #define CMD_ENABLE_CLICK 0x0A 10 | #define CMD_ENABLE_BELL 0x02 11 | #define CMD_DISABLE_BELL 0x03 12 | 13 | static const int sun_to_ascii[128] = { 14 | /* 0 */ 0, 15 | /* 1 */ 0, /* Stop */ 16 | /* 2 */ 0, /* Volume_Decr */ 17 | /* 3 */ 0, /* Again */ 18 | /* 4 */ 0, /* Volume_Incr */ 19 | /* 5 */ 194, /* F1 */ 20 | /* 6 */ 195, /* F2 */ 21 | /* 7 */ 203, /* F10 */ 22 | /* 8 */ 196, /* F3 */ 23 | /* 9 */ 204, /* F11 */ 24 | /* 10 */ 197, /* F4 */ 25 | /* 11 */ 205, /* F12 */ 26 | /* 12 */ 198, /* F5 */ 27 | /* 13 */ 0, 28 | /* 14 */ 199, /* F6 */ 29 | /* 15 */ 0, 30 | /* 16 */ 200, /* F7 */ 31 | /* 17 */ 201, /* F8 */ 32 | /* 18 */ 202, /* F9 */ 33 | /* 19 */ 130, /* Alt_L */ 34 | /* 20 */ 218, /* T5_Up */ 35 | /* 21 */ 0, /* Pause/Break */ 36 | /* 22 */ 0, /* Print_Screen */ 37 | /* 23 */ 0, /* Scroll_Lock */ 38 | /* 24 */ 216, /* T5_Left */ 39 | /* 25 */ 0, /* Props */ 40 | /* 26 */ 0, /* Undo */ 41 | /* 27 */ 217, /* T5_Down */ 42 | /* 28 */ 215, /* T5_Right */ 43 | /* 29 */ 177, /* Esc */ 44 | /* 30 */ 49, /* 1 */ 45 | /* 31 */ 50, /* 2 */ 46 | /* 32 */ 51, /* 3 */ 47 | /* 33 */ 52, /* 4 */ 48 | /* 34 */ 53, /* 5 */ 49 | /* 35 */ 54, /* 6 */ 50 | /* 36 */ 55, /* 7 */ 51 | /* 37 */ 56, /* 8 */ 52 | /* 38 */ 57, /* 9 */ 53 | /* 39 */ 48, /* 0 */ 54 | /* 40 */ 45, /* minus */ 55 | /* 41 */ 61, /* equal */ 56 | /* 42 */ 126, /* grave/tilde */ 57 | /* 43 */ 178, /* BackSpace */ 58 | /* 44 */ 209, /* T5_Insert */ 59 | /* 45 */ 0, /* Mute */ 60 | /* 46 */ 47, /* R5/KP_Div */ 61 | /* 47 */ 42, /* R6/KP_Mult */ 62 | /* 48 */ 0, /* Power */ 63 | /* 49 */ 0, /* Front */ 64 | /* 50 */ 46, /* KP_./KP_Delete */ 65 | /* 51 */ 0, /* Copy */ 66 | /* 52 */ 210, /* T5_Home */ 67 | /* 53 */ 179, /* Tab */ 68 | /* 54 */ 113, /* Q */ 69 | /* 55 */ 119, /* W */ 70 | /* 56 */ 101, /* E */ 71 | /* 57 */ 114, /* R */ 72 | /* 58 */ 116, /* T */ 73 | /* 59 */ 121, /* Y */ 74 | /* 60 */ 117, /* U */ 75 | /* 61 */ 105, /* I */ 76 | /* 62 */ 111, /* O */ 77 | /* 63 */ 112, /* P */ 78 | /* 64 */ 91, /* [ */ 79 | /* 65 */ 93, /* ] */ 80 | /* 66 */ 212, /* Delete */ 81 | /* 67 */ 0, 82 | /* 68 */ 55, /* KP_7/Home */ 83 | /* 69 */ 56, /* KP_8/Up */ 84 | /* 70 */ 57, /* KP_9/PgUp */ 85 | /* 71 */ 45, /* KP_Minus */ 86 | /* 72 */ 0, /* Open */ 87 | /* 73 */ 0, /* Paste */ 88 | /* 74 */ 213, /* T5_End */ 89 | /* 75 */ 0, 90 | /* 76 */ 128, /* Ctrl_L */ 91 | /* 77 */ 97, /* A */ 92 | /* 78 */ 115, /* S */ 93 | /* 79 */ 100, /* D */ 94 | /* 80 */ 102, /* F */ 95 | /* 81 */ 103, /* G */ 96 | /* 82 */ 104, /* H */ 97 | /* 83 */ 106, /* J */ 98 | /* 84 */ 107, /* K */ 99 | /* 85 */ 108, /* L */ 100 | /* 86 */ 59, /* ; */ 101 | /* 87 */ 39, /* apostr. */ 102 | /* 88 */ 92, /* backslash */ 103 | /* 89 */ 176, /* Return */ 104 | /* 90 */ 176, /* KP_Enter */ 105 | /* 91 */ 52, /* KP_4/Left */ 106 | /* 92 */ 53, /* KP_5/Center */ 107 | /* 93 */ 54, /* KP_6/Right */ 108 | /* 94 */ 48, /* KP_0/KP_Insert */ 109 | /* 95 */ 0, /* Find */ 110 | /* 96 */ 211, /* T5_PgUp */ 111 | /* 97 */ 0, /* Cut */ 112 | /* 98 */ 0, /* Num_Lock */ 113 | /* 99 */ 129, /* Shift_L */ 114 | /* 100 */ 122, /* Z */ 115 | /* 101 */ 120, /* X */ 116 | /* 102 */ 99, /* C */ 117 | /* 103 */ 118, /* V */ 118 | /* 104 */ 98, /* B */ 119 | /* 105 */ 110, /* N */ 120 | /* 106 */ 109, /* M */ 121 | /* 107 */ 44, /* , */ 122 | /* 108 */ 46, /* . */ 123 | /* 109 */ 47, /* / */ 124 | /* 110 */ 133, /* Shift_R */ 125 | /* 111 */ 0, 126 | /* 112 */ 49, /* KP_1/End */ 127 | /* 113 */ 50, /* KP_2/Down */ 128 | /* 114 */ 51, /* KP_3/PgDn */ 129 | /* 115 */ 0, 130 | /* 116 */ 0, 131 | /* 117 */ 0, 132 | /* 118 */ 0, /* Help */ 133 | /* 119 */ 193, /* CapsLock */ 134 | /* 120 */ 131, /* Meta_L */ 135 | /* 121 */ 32, /* SpaceBar */ 136 | /* 122 */ 135, /* Meta_R */ 137 | /* 123 */ 214, /* T5_PgDn */ 138 | /* 124 */ 0, 139 | /* 125 */ 43, /* KP_Add */ 140 | /* 126 */ 0, 141 | /* 127 */ 0 142 | }; 143 | -------------------------------------------------------------------------------- /SunKeyboard-Test/SunKeyboard-Test.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Test Program for Sun Type 5 Keyboard 3 | * Ben Rockwood 1/1/17 4 | * 5 | * Developed on Arduino Micro 6 | * MiniDIN 8a Adapter P/N: MD-80PL100 7 | * Wiring: 8 | * Keyboard Pin 2 (White): GND 9 | * Keyboard Pin 8 (Red): +5V 10 | * Keyboard Pin 6 (Yellow): Arduino Pin D10 (Serial RX) 11 | * Keyboard Pin 5 (Green): Aruidno Pin D11 (Serial TX) 12 | */ 13 | #include 14 | 15 | //Software serial for Sun KBD 16 | SoftwareSerial sunSerial(10, 11, true); 17 | 18 | void setup() { 19 | Serial.begin(1200); 20 | while (!Serial) { 21 | ; // wait for serial port to connect. Needed for Leonardo only 22 | } 23 | sunSerial.begin(1200); 24 | } 25 | 26 | void loop() { 27 | char c = sunSerial.read(); 28 | // Filter noise 29 | if (c != 0xFFFFFFFF) { 30 | Serial.print(c, DEC); Serial.print("\t0x"); 31 | Serial.print(c, HEX); Serial.print(":\t"); 32 | printKey(c); 33 | Serial.print("\n"); 34 | } 35 | } 36 | 37 | void printKey(int key){ 38 | if (key < 0) { 39 | key = 128 + key; 40 | Serial.print("Key Up: "); 41 | } else if (key == 127) { 42 | Serial.print("All Keys Released"); 43 | } else { 44 | Serial.print("Key Down: "); 45 | } 46 | 47 | // Keys mapped via data file processed with AWK for testing: 48 | switch(key){ 49 | case 29: // Esc 50 | Serial.print("Esc"); 51 | break; 52 | 53 | case 30: // 1 54 | Serial.print("1"); 55 | break; 56 | 57 | case 31: // 2 58 | Serial.print("2"); 59 | break; 60 | 61 | case 32: // 3 62 | Serial.print("3"); 63 | break; 64 | 65 | case 33: // 4 66 | Serial.print("4"); 67 | break; 68 | 69 | case 34: // 5 70 | Serial.print("5"); 71 | break; 72 | 73 | case 35: // 6 74 | Serial.print("6"); 75 | break; 76 | 77 | case 36: // 7 78 | Serial.print("7"); 79 | break; 80 | 81 | case 37: // 8 82 | Serial.print("8"); 83 | break; 84 | 85 | case 38: // 9 86 | Serial.print("9"); 87 | break; 88 | 89 | case 39: // 0 90 | Serial.print("0"); 91 | break; 92 | 93 | case 40: // minus 94 | Serial.print("minus"); 95 | break; 96 | 97 | case 41: // equal 98 | Serial.print("equal"); 99 | break; 100 | 101 | case 43: // BackSpace 102 | Serial.print("BackSpace"); 103 | break; 104 | 105 | case 53: // Tab 106 | Serial.print("Tab"); 107 | break; 108 | 109 | case 54: // Q 110 | Serial.print("Q"); 111 | break; 112 | 113 | case 55: // W 114 | Serial.print("W"); 115 | break; 116 | 117 | case 56: // E 118 | Serial.print("E"); 119 | break; 120 | 121 | case 57: // R 122 | Serial.print("R"); 123 | break; 124 | 125 | case 58: // T 126 | Serial.print("T"); 127 | break; 128 | 129 | case 59: // Y 130 | Serial.print("Y"); 131 | break; 132 | 133 | case 60: // U 134 | Serial.print("U"); 135 | break; 136 | 137 | case 61: // I 138 | Serial.print("I"); 139 | break; 140 | 141 | case 62: // O 142 | Serial.print("O"); 143 | break; 144 | 145 | case 63: // P 146 | Serial.print("P"); 147 | break; 148 | 149 | case 64: // [ 150 | Serial.print("["); 151 | break; 152 | 153 | case 65: // ] 154 | Serial.print("]"); 155 | break; 156 | 157 | case 89: // Return 158 | Serial.print("Return"); 159 | break; 160 | 161 | case 76: // Ctrl_L 162 | Serial.print("Ctrl_L"); 163 | break; 164 | 165 | case 77: // A 166 | Serial.print("A"); 167 | break; 168 | 169 | case 78: // S 170 | Serial.print("S"); 171 | break; 172 | 173 | case 79: // D 174 | Serial.print("D"); 175 | break; 176 | 177 | case 80: // F 178 | Serial.print("F"); 179 | break; 180 | 181 | case 81: // G 182 | Serial.print("G"); 183 | break; 184 | 185 | case 82: // H 186 | Serial.print("H"); 187 | break; 188 | 189 | case 83: // J 190 | Serial.print("J"); 191 | break; 192 | 193 | case 84: // K 194 | Serial.print("K"); 195 | break; 196 | 197 | case 85: // L 198 | Serial.print("L"); 199 | break; 200 | 201 | case 86: // ; 202 | Serial.print(";"); 203 | break; 204 | 205 | case 87: // apostr. 206 | Serial.print("apostr."); 207 | break; 208 | 209 | case 42: // grave/tilde 210 | Serial.print("grave/tilde"); 211 | break; 212 | 213 | case 99: // Shift_L 214 | Serial.print("Shift_L"); 215 | break; 216 | 217 | case 88: // backslash 218 | Serial.print("backslash"); 219 | break; 220 | 221 | case 100: // Z 222 | Serial.print("Z"); 223 | break; 224 | 225 | case 101: // X 226 | Serial.print("X"); 227 | break; 228 | 229 | case 102: // C 230 | Serial.print("C"); 231 | break; 232 | 233 | case 103: // V 234 | Serial.print("V"); 235 | break; 236 | 237 | case 104: // B 238 | Serial.print("B"); 239 | break; 240 | 241 | case 105: // N 242 | Serial.print("N"); 243 | break; 244 | 245 | case 106: // M 246 | Serial.print("M"); 247 | break; 248 | 249 | case 107: // , 250 | Serial.print(","); 251 | break; 252 | 253 | case 108: // . 254 | Serial.print("."); 255 | break; 256 | 257 | case 109: // / 258 | Serial.print("/"); 259 | break; 260 | 261 | case 110: // Shift_R 262 | Serial.print("Shift_R"); 263 | break; 264 | 265 | case 47: // R6/KP_Mult 266 | Serial.print("R6/KP_Mult"); 267 | break; 268 | 269 | case 120: // Meta_L 270 | Serial.print("Meta_L"); 271 | break; 272 | 273 | case 121: // SpaceBar 274 | Serial.print("SpaceBar"); 275 | break; 276 | 277 | case 119: // CapsLock 278 | Serial.print("CapsLock"); 279 | break; 280 | 281 | case 5: // F1 282 | Serial.print("F1"); 283 | break; 284 | 285 | case 6: // F2 286 | Serial.print("F2"); 287 | break; 288 | 289 | case 8: // F3 290 | Serial.print("F3"); 291 | break; 292 | 293 | case 10: // F4 294 | Serial.print("F4"); 295 | break; 296 | 297 | case 12: // F5 298 | Serial.print("F5"); 299 | break; 300 | 301 | case 14: // F6 302 | Serial.print("F6"); 303 | break; 304 | 305 | case 16: // F7 306 | Serial.print("F7"); 307 | break; 308 | 309 | case 17: // F8 310 | Serial.print("F8"); 311 | break; 312 | 313 | case 18: // F9 314 | Serial.print("F9"); 315 | break; 316 | 317 | case 7: // F10 318 | Serial.print("F10"); 319 | break; 320 | 321 | case 68: // R7/KP_7/Home 322 | Serial.print("R7/KP_7/Home"); 323 | break; 324 | 325 | case 69: // R8/KP_8/Up 326 | Serial.print("R8/KP_8/Up"); 327 | break; 328 | 329 | case 70: // R9/KP_9/PgUp 330 | Serial.print("R9/KP_9/PgUp"); 331 | break; 332 | 333 | case 71: // KP_Minus 334 | Serial.print("KP_Minus"); 335 | break; 336 | 337 | case 91: // R10/KP_4/Left 338 | Serial.print("R10/KP_4/Left"); 339 | break; 340 | 341 | case 92: // R11/KP_5/Center 342 | Serial.print("R11/KP_5/Center"); 343 | break; 344 | 345 | case 93: // R12/KP_6/Right 346 | Serial.print("R12/KP_6/Right"); 347 | break; 348 | 349 | case 125: // KP_Add 350 | Serial.print("KP_Add"); 351 | break; 352 | 353 | case 112: // R13/KP_1/End 354 | Serial.print("R13/KP_1/End"); 355 | break; 356 | 357 | case 113: // R14/KP_2/Down 358 | Serial.print("R14/KP_2/Down"); 359 | break; 360 | 361 | case 114: // R15/KP_3/PgDn 362 | Serial.print("R15/KP_3/PgDn"); 363 | break; 364 | 365 | case 94: // KP_0/KP_Insert 366 | Serial.print("KP_0/KP_Insert"); 367 | break; 368 | 369 | case 50: // KP_./KP_Delete 370 | Serial.print("KP_./KP_Delete"); 371 | break; 372 | 373 | case 9: // F11 374 | Serial.print("F11"); 375 | break; 376 | 377 | case 11: // F12 378 | Serial.print("F12"); 379 | break; 380 | 381 | case 90: // KP_Enter 382 | Serial.print("KP_Enter"); 383 | break; 384 | 385 | case 46: // R5/KP_Div 386 | Serial.print("R5/KP_Div"); 387 | break; 388 | 389 | case 122: // Meta_R 390 | Serial.print("Meta_R"); 391 | break; 392 | 393 | case 52: // T5_Home 394 | Serial.print("T5_Home"); 395 | break; 396 | 397 | case 20: // T5_Up 398 | Serial.print("T5_Up"); 399 | break; 400 | 401 | case 96: // T5_PgUp 402 | Serial.print("T5_PgUp"); 403 | break; 404 | 405 | case 24: // T5_Left 406 | Serial.print("T5_Left"); 407 | break; 408 | 409 | case 28: // T5_Right 410 | Serial.print("T5_Right"); 411 | break; 412 | 413 | case 74: // T5_End 414 | Serial.print("T5_End"); 415 | break; 416 | 417 | case 27: // T5_Down 418 | Serial.print("T5_Down"); 419 | break; 420 | 421 | case 123: // T5_PgDn 422 | Serial.print("T5_PgDn"); 423 | break; 424 | 425 | case 44: // T5_Insert 426 | Serial.print("T5_Insert"); 427 | break; 428 | 429 | case 66: // Delete 430 | Serial.print("Delete"); 431 | break; 432 | 433 | case 19: // Alt_L 434 | Serial.print("Alt_L"); 435 | break; 436 | } 437 | } 438 | 439 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # USB-to-Sun Keyboard Adapter using Arduino Micro 2 | 3 | It's my firm belief that the best keyboard in history is the Sun Type 5 UNIX Layout. It big, heavy, chunky, blocky, and feels wonderful to me. What's more? It's _the_ UNIX keyboard and the first keyboard I ever fell in love with. Sadly, the Sun Type 5 only works with Sun workstations. 4 | 5 | The Type 6 keyboard was available with USB, and thats the keyboard I use every day, but it was sleaked down from the chunky glory that was the Type 5. The Type 7 was something of a middle-ground, the blocky figure of the Type 5 but it was made with cheap plastics and lacked the heaft of the Type 5. 6 | 7 | So, for the last 10+ years I've had a dream of converting Sun Type 5 to USB so I can live the dream. Commercially available adapters have been on the market forever, but they typically cost $150+, outside 8 | of my budget. Some adventurous souls have created their own adapters, but they seemed overly complicated given the task. What I _really_ wanted was to create my own, simple, affordable adapter. 9 | 10 | Last month I came across an Adafruit tutorial that rekindled my old desire: 11 | [USB NeXT Keyboard with an Arduino Micro](https://learn.adafruit.com/usb-next-keyboard-with-arduino-micro/overview). The links provided happened to include the pin-out of the Sun Type 4/5/6 keyboards and some pointers on how 12 | to build the adapter. So I found the right plug on [Mouser](http://www.mouser.com/ProductDetail/CUI-Inc/MD-80PL100/) 13 | and on New Years Eve got to hacking on it. New Years day I had a working Sun Type 5 on my MacBook! 14 | 15 | # How to Build 16 | 17 | You will require: 18 | 19 | * An Arduino based on the Atmel 32u4 chip, these are required by the [Arduino Mouse & Keyboard libraries](https://www.arduino.cc/en/Reference/MouseKeyboard) 20 | which you'll need for the Arduino to act as a keyboard adapter 21 | * A USB Type A to USB Micro B cable to attach the Arduino to your computer 22 | * An [MD-80PL100](http://www.mouser.com/ProductDetail/CUI-Inc/MD-80PL100/) Mini-Din 8a (female) panel connector 23 | * A Sun Type 5 Keyboard! (UNIX Layout preferably!) 24 | 25 | The Sun keyboard uses a Mini-Din 8a connector. Thanks to Alexander Kurz you can find the [Sun Type 4/5/6 Pinout](http://www.kbdbabel.org/conn/index.html) on kbdbabel.org: 26 | 27 | ![Keyboard Pinout](http://www.kbdbabel.org/conn/kbd_connector_sun456.png) 28 | 29 | You'll notice that they keyboard has its own Vcc +5v & Ground as well as a "from keyboard" and "to keyboard". You also have 3 more wires providing Vcc +5V & Ground plus a single read line for the mouse! (We'll ignore the mouse for now). 30 | 31 | Lets connect to our Arduino! If you buy the MD-80PL100 I recommended above ([PDF datasheet](http://www.mouser.com/ds/2/670/md-xxpl100-series-516094.pdf)]), the write mapping will be: 32 | 33 | | Keyboard Plug | Arduino | 34 | |----------------|-----------------| 35 | | Pin 2 (White) | GND | 36 | | Pin 8 (Red) | +5V | 37 | | Pin 6 (Yellow) | D10 (Serial RX) | 38 | | Pin 5 (Green) | D11 (Serial TX) | 39 | 40 | Wire it up and then you just need to upload the sketch! 41 | 42 | # Packaging Ideas 43 | 44 | If you are just playing around with a Sun keyboard, build it on a breadboard and then reclaim the parts for other projects.... but if you want to build a perminant solution, read on. 45 | 46 | There are several ways you can package this solution. As of January 2017 there are no Arduiono Micro's sold without headers. The knock-off Micro's on Amazon all have bad reviews, so I'm avoiding them. You can either de-solder the headers on a genuine Micro or use snips to clip off the leads for packaging. 47 | 48 | One idea is to follow Adafruits favorite pattern and use an Altiods tin like they did for their [NeXT Keyboard adapter](https://learn.adafruit.com/usb-next-keyboard-with-arduino-micro/wiring). 49 | 50 | Another option is to perminantly build this adapter into a Sun keyboard. If you open the case of the keyboard you'll find the circuit board on one side but a lot of extra room on the other. Using non-conductive epoxy or foam tape (such as 3M VHB Tape RP32) you could mount the Arduino right inside, exposing only the USB cable. If you do this and are willing to damage the keyboard perminantly, you could cut off the cable and splice (or de-solder it completely), connecting directly to the Arduino bypassing the Mini-Din connector completely! 51 | 52 | # How the Keyboard and Software Works 53 | 54 | This solution is gloriously simple! The simplicity is thanks to the capabilities of the Arduino hardware/software and the cleverness of Sun engineers. 55 | 56 | The Sun Keyboard is actually a 1200 baud serial device. Seriuosly. That sounds odd but is actually wonderful because the Arduino can easily interface with it using the [Serial Library](https://www.arduino.cc/en/Reference/Serial). We can also use the Arduino [Keyboard/Mouse Library](https://www.arduino.cc/en/Reference/MouseKeyboard) to write to the computer. Therefore, all we need to do is read from the serial output of the keyboard, translate each key from the Sun scancode to the ASCII equivilent and then write the ASCII to our computer as keyboard input! 57 | 58 | By using the Arduino Serial Monitor and a simple sketch to listen, we can see what they keyboard is sending. Press "a" on the keyboard and we get the following (decimal) output to the monitor: 59 | 60 | ``` 61 | 77 62 | -51 63 | 127 64 | ``` 65 | 66 | After some playing around, you'll realize that the 3 values send by the keyboard have 3 meanings represending different actions: 67 | 68 | 1. **77**: 77 is the code representing the "a" key being pressed down 69 | 2. **-51**: This indicates the key being released (key up), but which key? Add this value to 128 to determine the key! 128-51=77, so the "a" key is being released. _Clever right!?!_ 70 | 3. **127**: This code is sent when no other key is being pressed, it is the "all clear" message. 71 | 72 | You can verify this all by pressing and holding "a", then pressing and holding "b", then "c", and then release each key one at a time. You'll clearly see the key downs, key ups, and releases. 73 | 74 | It just so happens that these map perfectly to our Arduino library! 75 | 76 | In **SunKeyboard-to-USB/sun_keyboard_map.h** I created an array mapping the Sun scancode (as the array index) to the equivilent ASCII charactor. You'll notice several keys map to "0" because they aren't supported by the Keyboard library (or PC's for that matter). By messing with this array you can re-map keys as you wish (such as making Caps Locks Control for PC Layout). 77 | 78 | Once you have the Sun to ASCII map worked out, everything is simple! We listen on Serial for input. If we get a number between 1 and 126 we look it up in the array and then pass the result (ASCII) to Keyboard.press(). If we get a number less than 0 we know this is a key-up event, so we add to 128 to find the key which we then lookup in the array and pass to Keyboard.release(). Finally, if we get 127 as input, we know that no keys are being pressed, so we send Keyboard.releaseAll()! 79 | 80 | Couldn't be simpler. 81 | 82 | ## LED Control & Sending Commands to the Keyboard 83 | 84 | Commands can be sent on the serial line to the keyboard. Because they aren't emitted from the keyboard its harder to discover them through trial-and-error, thankfully in my search I finally found the document I needed from the beginning: [The SPARC International: SPARC Keyboard Specification](http://sparc.org/wp-content/uploads/2014/01/KBD.pdf.gz). Contained within are the pinouts, the scancodes, and most importantly the serial commands! On page 17 of the PDF you'll find the serial protocal and the commands you can send: 85 | 86 | * **0x01**: Reset 87 | * **0x02**: Bell On 88 | * **0x03**: Bell Off 89 | * **0x0A**: Keyboard Click On 90 | * **0x0B**: Keyboard Click Off 91 | * **0x0E**: LED Command 92 | * **0x0F**: Layout Command 93 | 94 | The Bell is simply a loud computer speaker sound. Normally it should only be used in short bursts (like the one your PC makes when it turns on) by sending 0x02, then delay 100ms, then send 0x03 to turn off. Once turned on it will make a solid tone until you turn it off. 95 | 96 | The Keyboard Click is something you may remember from the old WYSE & HP Terminal days. When enabled you will get a little "chirp" sound every time you press a key. It brings back nostalgia for about 10 seconds and then is incredibly annoying. 97 | 98 | I'm not using the Layout command because I found the scan codes for both PC & UNIX layouts are the same, so I don't currently see a need for this. 99 | 100 | The Reset seemed promising but ultimately I found little utility in it. I experimented with sending it during keyboard setup in my Arduino code, but it seemed to have no utility. 101 | 102 | The LED Command is the important one. You must send 2 bytes, the first is the LED Command 0x0E and the second is a 4-bit bitmask which determines which of the 4 LED's are on or off: 103 | 104 | ``` 105 | 0000 All off 106 | 0001 Numlock == 1 107 | 0010 Compose == 2 108 | 0100 Scroll == 4 109 | 1000 Caps Lock == 8 110 | ``` 111 | 112 | Serial.write() can only pass a single value, so using 2 in sequence was hit or miss, so instead I created a 2 byte array, the first element is the LED Command 0x0E and the second is the value of the bitmask. Then I can pass that array to Serial.write as a single unit. Rather than manipulate the mask via bitwise operators and make the code most complex I instead stuck with the poor-mans method of simply adding or subtracting the decimal values to the mask. So to enable Caps lock, add 8 to the mask, to turn off, subtract 8. The effect of this is that you must keep the state of the LEDs in your controller, and therefore I re-initialize the LEDs on each load in setup() to a known state. 113 | 114 | I found that on my Mac & Linux systems when Caps Lock is pressed the OS handles translation of keys for me, so I don't need to alter the scan code interpretations. However, the [Keyboard Modifiers](https://www.arduino.cc/en/Reference/KeyboardModifiers) do not include a mapping for Number lock... howerver after digging I [found](https://learn.adafruit.com/introducing-bluefruit-ez-key-diy-bluetooth-hid-keyboard/sending-keys-via-serial) the [extended ASCII scan codes](https://en.wikipedia.org/wiki/ASCII) elsewhere to provide mapping. I may add Number Lock in the future, but for now it is simply fixed for simplicity. 115 | 116 | 117 | 118 | ## Bonus Features 119 | 120 | The Keyboard has a speaker built in and you can enable a "bell" (annoying!) and "key chirp". I have mapped these to the top-right 4 keys: 121 | 122 | * Mute Key: Disable Chirp Mode 123 | * Decrease Volume Key: Enable Chirp Mode 124 | * Increase Volume Key: Turn on Bell (constant sound) 125 | * Power Key: Turn off Bell 126 | 127 | ## What doesn't work (yet) 128 | 129 | * Scroll Lock and Compose don't function by design; there is no practical use for them and don't see a reason to add the 10 lines of logic 130 | * I force Number lock on and you can not toggle it (may fix in the future) 131 | * All Sun specific keys do not work (but you can remap them how you wish), this is a limitation of the way the Arduino Keyboard library emulates the keyboard. I may find a fix for it in the future, but not planned. 132 | * The passthrough mouse doesn't work, but I didn't like it anyway.. may or may not add in the future 133 | 134 | # Acknowledgements 135 | 136 | * Arduino.cc 137 | * Adafruit 138 | * Alexander Kurz's awesome Keyboard Pin-outs 139 | --------------------------------------------------------------------------------