├── examples └── terminal_bluefruit_converter │ ├── include_api.cpp │ ├── include_tmk.c │ ├── config.h │ └── terminal_bluefruit_converter.ino ├── .gitmodules ├── api ├── include.cpp ├── KeyboardKey.cpp ├── MouseReport.cpp ├── DummyMatrix.cpp ├── KeyboardReport.cpp ├── PS2Matrix.cpp ├── KeyboardHost.cpp ├── KeyboardFirmware.cpp ├── BluefruitHost.cpp └── PS2MatrixCodeset3.cpp ├── .gitignore ├── KeyboardKey.h ├── MouseReport.h ├── KeyboardReport.h ├── KeyboardHost.h ├── tmk ├── include.c ├── xprintf.h ├── gluecode.c └── xprintf.c ├── BluefruitHost.h ├── DummyMatrix.h ├── PS2Matrix.h ├── KeyboardMatrix.h ├── KeyboardFirmware.h ├── README.md ├── PS2MatrixCodeset3.h └── gluecode.h /examples/terminal_bluefruit_converter/include_api.cpp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | -------------------------------------------------------------------------------- /examples/terminal_bluefruit_converter/include_tmk.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tmk/tmk_keyboard"] 2 | path = tmk/tmk_keyboard 3 | url = git://github.com/bgould/tmk_keyboard.git 4 | -------------------------------------------------------------------------------- /api/include.cpp: -------------------------------------------------------------------------------- 1 | #include "KeyboardFirmware.cpp" 2 | #include "KeyboardHost.cpp" 3 | #include "KeyboardKey.cpp" 4 | #include "KeyboardReport.cpp" 5 | #include "MouseReport.cpp" 6 | #include "BluefruitHost.cpp" 7 | #include "PS2Matrix.cpp" 8 | #include "PS2MatrixCodeset3.cpp" 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | 15 | # target folder 16 | KeyboardConverter 17 | 18 | # project files 19 | *.geany 20 | 21 | 22 | -------------------------------------------------------------------------------- /api/KeyboardKey.cpp: -------------------------------------------------------------------------------- 1 | #include "KeyboardKey.h" 2 | 3 | KeyboardKey::KeyboardKey(uint8_t row, uint8_t col) { 4 | _row = row; 5 | _col = col; 6 | } 7 | 8 | uint8_t KeyboardKey::getRow() { 9 | return _row; 10 | } 11 | 12 | uint8_t KeyboardKey::getCol() { 13 | return _col; 14 | } 15 | -------------------------------------------------------------------------------- /KeyboardKey.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYBOARD_KEY_H 2 | #define KEYBOARD_KEY_H 1 3 | 4 | #include "Arduino.h" 5 | 6 | class KeyboardKey { 7 | public: 8 | KeyboardKey(uint8_t row, uint8_t col); 9 | uint8_t getRow(void); 10 | uint8_t getCol(void); 11 | private: 12 | uint8_t _row; 13 | uint8_t _col; 14 | }; 15 | 16 | #endif 17 | 18 | -------------------------------------------------------------------------------- /MouseReport.h: -------------------------------------------------------------------------------- 1 | #ifndef MOUSEREPORT_H 2 | #define MOUSEREPORT_H 3 | 4 | #include "KeyboardFirmware.h" 5 | 6 | class MouseReport 7 | { 8 | public: 9 | MouseReport(report_mouse_t *report); 10 | uint8_t getButtons(); 11 | uint8_t getX(); 12 | uint8_t getY(); 13 | uint8_t getV(); 14 | uint8_t getH(); 15 | private: 16 | report_mouse_t *_report; 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /KeyboardReport.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYBOARDREPORT_H 2 | #define KEYBOARDREPORT_H 3 | 4 | #include "KeyboardFirmware.h" 5 | 6 | class KeyboardReport 7 | { 8 | public: 9 | KeyboardReport(report_keyboard_t *report); 10 | uint8_t getModifiers(); 11 | uint8_t getReserved(); 12 | uint8_t getReportKeys(); 13 | uint8_t getKey(uint8_t keyIndex); 14 | private: 15 | report_keyboard_t *_report; 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /KeyboardHost.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYBOARDHOST_H 2 | #define KEYBOARDHOST_H 3 | 4 | #include "KeyboardReport.h" 5 | #include "MouseReport.h" 6 | 7 | class KeyboardHost 8 | { 9 | public: 10 | virtual void begin() = 0; 11 | virtual void sendKeyboard(KeyboardReport &report) = 0; 12 | virtual void sendMouse(MouseReport &report) = 0; 13 | virtual void sendConsumer(uint16_t data) = 0; 14 | virtual void sendSystem(uint16_t data) = 0; 15 | virtual uint8_t getLEDs(void) = 0; 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /api/MouseReport.cpp: -------------------------------------------------------------------------------- 1 | #include "MouseReport.h" 2 | 3 | MouseReport::MouseReport(report_mouse_t *report) 4 | { 5 | _report = report; 6 | } 7 | 8 | byte MouseReport::getButtons() 9 | { 10 | return _report->buttons; 11 | } 12 | 13 | byte MouseReport::getX() 14 | { 15 | return _report->x; 16 | } 17 | 18 | byte MouseReport::getY() 19 | { 20 | return _report->y; 21 | } 22 | 23 | byte MouseReport::getV() 24 | { 25 | return _report->v; 26 | } 27 | 28 | byte MouseReport::getH() 29 | { 30 | return _report->h; 31 | } 32 | -------------------------------------------------------------------------------- /tmk/include.c: -------------------------------------------------------------------------------- 1 | #include "gluecode.c" 2 | #include "xprintf.c" 3 | #include "tmk/tmk_keyboard/common/action.c" 4 | #include "tmk/tmk_keyboard/common/action_layer.c" 5 | #include "tmk/tmk_keyboard/common/action_macro.c" 6 | #include "tmk/tmk_keyboard/common/action_tapping.c" 7 | #include "tmk/tmk_keyboard/common/action_util.c" 8 | #include "tmk/tmk_keyboard/common/host.c" 9 | #include "tmk/tmk_keyboard/common/keymap.c" 10 | #include "tmk/tmk_keyboard/protocol/ps2_busywait.c" 11 | #include "tmk/tmk_keyboard/common/util.c" 12 | 13 | #if MOUSEKEY_ENABLE 14 | #include "tmk/tmk_keyboard/common/mousekey.c" 15 | #endif 16 | -------------------------------------------------------------------------------- /BluefruitHost.h: -------------------------------------------------------------------------------- 1 | #ifndef BLUEFRUITHOST_H 2 | #define BLUEFRUITHOST_H 1 3 | 4 | #include "KeyboardFirmware.h" 5 | 6 | class BluefruitHost : public KeyboardHost 7 | { 8 | public: 9 | BluefruitHost(); 10 | virtual void begin(); 11 | virtual void sendKeyboard(KeyboardReport &report); 12 | virtual void sendMouse(MouseReport &report); 13 | virtual void sendConsumer(uint16_t data); 14 | virtual void sendSystem(uint16_t data); 15 | virtual uint8_t getLEDs(); 16 | protected: 17 | void _serial_send(uint8_t data); 18 | private: 19 | uint16_t _last_consumer_data; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /DummyMatrix.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | 3 | #ifndef DUMMYMATRIX_H 4 | #define DUMMYMATRIX_H 1 5 | 6 | #define MATRIX_ROWS 1 7 | #define MATRIX_COLS 8 8 | 9 | #include "KeyboardFirmware.h" 10 | 11 | class DummyMatrix : public KeyboardMatrix 12 | { 13 | public: 14 | DummyMatrix(); 15 | void begin(); 16 | uint8_t scan(void); 17 | uint8_t getRows(); 18 | uint8_t getCols(); 19 | bool isOn(uint8_t row, uint8_t col); 20 | matrix_row_t getRow(uint8_t row); 21 | #if DEBUG_ENABLE 22 | void debugPrint(void); 23 | #endif 24 | private: 25 | uint8_t _row; 26 | int _loops; 27 | }; 28 | 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /PS2Matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef PS2MATRIX_H 2 | #define PS2MATRIX_H 1 3 | 4 | #include "KeyboardFirmware.h" 5 | 6 | #define PS2_ROW(code) (code>>3) 7 | #define PS2_COL(code) (code&0x07) 8 | 9 | class PS2Matrix : public KeyboardMatrix 10 | { 11 | public: 12 | PS2Matrix(); 13 | virtual void begin(); 14 | virtual uint8_t scan() = 0; 15 | virtual uint8_t getRows() = 0; 16 | virtual uint8_t getCols() = 0; 17 | virtual bool isOn(uint8_t row, uint8_t col); 18 | bool isGhostInRow(uint8_t row); 19 | virtual matrix_row_t getRow(uint8_t row); 20 | virtual void debugPrint(void); 21 | protected: 22 | void _make(uint8_t code); 23 | void _break(uint8_t code); 24 | uint8_t _matrix[MATRIX_ROWS]; 25 | bool _is_modified; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /examples/terminal_bluefruit_converter/config.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYBOARDFIRMWARE_CONFIG_H 2 | #define KEYBOARDFIRMWARE_CONFIG_H 1 3 | 4 | #define RESET_BUTTON_PIN 8 5 | #define PAIR_LED_PIN 7 6 | #define PAIR_BUTTON_PIN 6 7 | #define OUTPUT_LED_PIN 5 8 | #define KEY_LED_PIN 4 9 | #define OUTPUT_LED_ON HIGH 10 | #define OUTPUT_LED_OFF LOW 11 | #define DEBUGGING_LED 13 12 | #define DEBUGGING_LED_ON HIGH 13 | #define DEBUGGING_LED_OFF LOW 14 | 15 | #define DEBUG_ENABLE false 16 | 17 | #define EXTRAKEY_ENABLE 1 18 | #define MOUSEKEY_ENABLE 1 19 | 20 | #define MATRIX_ROWS 17 21 | #define MATRIX_COLS 8 22 | 23 | #define PS2_CLOCK_PORT PORTD 24 | #define PS2_CLOCK_PIN PIND 25 | #define PS2_CLOCK_DDR DDRD 26 | #define PS2_CLOCK_BIT 1 27 | 28 | #define PS2_DATA_PORT PORTD 29 | #define PS2_DATA_PIN PIND 30 | #define PS2_DATA_DDR DDRD 31 | #define PS2_DATA_BIT 0 32 | 33 | #define PS2_USE_BUSYWAIT true 34 | 35 | #ifndef PS2_MATRIX_HAS_GHOSTING 36 | #define PS2_MATRIX_HAS_GHOSTING true 37 | #endif 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /KeyboardMatrix.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYBOARDMATRIX_H 2 | #define KEYBOARDMATRIX_H 1 3 | 4 | #include "KeyboardFirmware.h" 5 | 6 | /* translates Fn keycode to action */ 7 | //action_t keymap_fn_to_action(uint8_t keycode); 8 | 9 | #if (MATRIX_COLS <= 8) 10 | typedef uint8_t matrix_row_t; 11 | #elif (MATRIX_COLS <= 16) 12 | typedef uint16_t matrix_row_t; 13 | #elif (MATRIX_COLS <= 32) 14 | typedef uint32_t matrix_row_t; 15 | #else 16 | #error "MATRIX_COLS: invalid value" 17 | #endif 18 | 19 | #define MATRIX_IS_ON(row, col) (matrix_get_row(row) && (1<mods; 34 | } 35 | 36 | uint8_t KeyboardReport::getReserved() 37 | { 38 | return _report->reserved; 39 | } 40 | 41 | uint8_t KeyboardReport::getKey(uint8_t keyIndex) 42 | { 43 | return _report->keys[keyIndex]; 44 | } 45 | 46 | uint8_t KeyboardReport::getReportKeys() 47 | { 48 | return REPORT_KEYS; 49 | } 50 | -------------------------------------------------------------------------------- /KeyboardFirmware.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYBOARDFIRMWARE_H 2 | #define KEYBOARDFIRMWARE_H 1 3 | 4 | #define START_KEYMAPS extern "C" { 5 | 6 | #define KEYMAPS static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] 7 | 8 | #define FN_ACTIONS static const uint16_t fn_actions[] PROGMEM 9 | 10 | #define KEYMAPS_FINISHED uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) { \ 11 | return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); \ 12 | } \ 13 | action_t keymap_fn_to_action(uint8_t keycode) { \ 14 | action_t action; \ 15 | action.code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]); \ 16 | return action; \ 17 | } \ 18 | } 19 | 20 | #include "Arduino.h" 21 | #include "gluecode.h" 22 | #include "KeyboardKey.h" 23 | #include "KeyboardMatrix.h" 24 | #include "KeyboardHost.h" 25 | #include "KeyboardReport.h" 26 | #include "MouseReport.h" 27 | #include "BluefruitHost.h" 28 | #include "PS2Matrix.h" 29 | #include "PS2MatrixCodeset3.h" 30 | 31 | class KeyboardFirmware_ 32 | { 33 | public: 34 | KeyboardFirmware_(); 35 | void runTask(void); 36 | void begin(KeyboardHost &host, KeyboardMatrix &matrix); 37 | void setLEDs(uint8_t leds); 38 | KeyboardHost* getHost(); 39 | KeyboardMatrix* getMatrix(); 40 | private: 41 | KeyboardHost *_host; 42 | KeyboardMatrix *_matrix; 43 | }; 44 | 45 | extern KeyboardFirmware_ KeyboardFirmware; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /tmk/xprintf.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------*/ 2 | /* Universal string handler for user console interface (C)ChaN, 2011 */ 3 | /*------------------------------------------------------------------------*/ 4 | 5 | #ifndef _STRFUNC 6 | #define _STRFUNC 7 | 8 | #define _USE_XFUNC_OUT 1 /* 1: Use output functions */ 9 | #define _CR_CRLF 1 /* 1: Convert \n ==> \r\n in the output char */ 10 | 11 | #define _USE_XFUNC_IN 0 /* 1: Use input function */ 12 | #define _LINE_ECHO 1 /* 1: Echo back input chars in xgets function */ 13 | 14 | 15 | #if _USE_XFUNC_OUT 16 | #define xdev_out(func) xfunc_out = (void(*)(unsigned char))(func) 17 | extern void (*xfunc_out)(unsigned char); 18 | void xputc (char c); 19 | void xputs (const char* str); 20 | void xfputs (void (*func)(unsigned char), const char* str); 21 | void xprintf (const char* fmt, ...); 22 | void xsprintf (char* buff, const char* fmt, ...); 23 | void xfprintf (void (*func)(unsigned char), const char* fmt, ...); 24 | void put_dump (const void* buff, unsigned long addr, int len, int width); 25 | #define DW_CHAR sizeof(char) 26 | #define DW_SHORT sizeof(short) 27 | #define DW_LONG sizeof(long) 28 | #endif 29 | 30 | #if _USE_XFUNC_IN 31 | #define xdev_in(func) xfunc_in = (unsigned char(*)(void))(func) 32 | extern unsigned char (*xfunc_in)(void); 33 | int xgets (char* buff, int len); 34 | int xfgets (unsigned char (*func)(void), char* buff, int len); 35 | int xatoi (char** str, long* res); 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /api/PS2Matrix.cpp: -------------------------------------------------------------------------------- 1 | #include "PS2Matrix.h" 2 | 3 | PS2Matrix::PS2Matrix() 4 | { 5 | } 6 | 7 | void PS2Matrix::begin() 8 | { 9 | dprintf("[ Initializing PS2 matrix ]\n"); 10 | ps2_host_init(); 11 | 12 | for (uint8_t i = 0, c = getRows(); i < c; i++) _matrix[i] = 0x00; 13 | } 14 | 15 | bool PS2Matrix::isOn(uint8_t row, uint8_t col) 16 | { 17 | return (_matrix[row] & (1< 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 | * MA 02110-1301, USA. 20 | * 21 | * 22 | */ 23 | #include "gluecode.h" 24 | 25 | void exec_action(uint8_t r, uint8_t c, matrix_row_t matrix_row) { 26 | action_exec((keyevent_t){ 27 | .key = (key_t){ .row = r, .col = c }, 28 | .pressed = (matrix_row & ((matrix_row_t)1<getLEDs(); 9 | } 10 | 11 | void host_keyboard_send(report_keyboard_t *report) { 12 | 13 | } 14 | 15 | void host_mouse_send(report_mouse_t *report) { 16 | } 17 | 18 | void host_system_send(uint16_t data) { 19 | } 20 | 21 | void host_consumer_send(uint16_t data) { 22 | } 23 | 24 | uint16_t host_last_sysytem_report(void) { 25 | return last_system_report; 26 | } 27 | 28 | uint16_t host_last_consumer_report(void) { 29 | return last_consumer_report; 30 | } 31 | */ 32 | 33 | //#include "tmk_host.h" 34 | 35 | /* 36 | static uint8_t keyboard_leds(void); 37 | static void send_keyboard(report_keyboard_t *report); 38 | static void send_mouse(report_mouse_t *report); 39 | static void send_system(uint16_t data); 40 | static void send_consumer(uint16_t data); 41 | 42 | // Not implemented yet 43 | static uint8_t keyboard_leds(void) {} 44 | static void send_system(uint16_t data) {} 45 | 46 | // Ugly. We'll keep the last KeyboardHost in a global 47 | // Better might be to use a data structure to support multiple hosts 48 | static KeyboardHost *_global_host; 49 | 50 | static void send_keyboard(report_keyboard_t *report_t) { 51 | KeyboardReport *report = new KeyboardReport(report_t); 52 | _global_host->sendKeyboard(report); 53 | delete report; 54 | } 55 | 56 | static void send_mouse(report_mouse_t *report_t) { 57 | MouseReport *report = new MouseReport(report_t); 58 | _global_host->sendMouse(report); 59 | delete report; 60 | } 61 | 62 | static void send_consumer(uint16_t data) { 63 | _global_host->sendConsumer(data); 64 | } 65 | 66 | host_driver_t* KeyboardHost::asHostDriver() 67 | { 68 | _global_host = this; 69 | host_driver_t driver = { 70 | keyboard_leds, 71 | send_keyboard, 72 | send_mouse, 73 | send_system, 74 | send_consumer 75 | }; 76 | return &driver; 77 | } 78 | */ 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | arduino_tmk_keyboard 2 | ==================== 3 | 4 | Simple (and incomplete) Arduino/C++ wrapper for the fantastic [TMK Keyboard Firmware](http://github.com/tmk/tmk_keyboard) 5 | 6 | This implementation is "incomplete" because at the moment the only provided protocol is PS/2, and the only host implementation is for the excellent Bluefruit EZ-Key HID from Adafruit Industries. 7 | 8 | If you have the ability to compile & load AVR C code onto your microcontroller, there is nothing that this library provides that you could not do directly with tmk_keyboard. However you may be interested in this project if you want to: 9 | * compile and load keyboard or converter firmware in the Arduino IDE 10 | * utilize object oriented techniques to create new implementations of the tmk_keyboard components (host, matrix, etc) 11 | * utilize other Arduino libraries in custom tmk_keyboard action functions 12 | * allow your Arduino project to utilize existing keyboard or mouse hardware for input 13 | * make your Arduino project appear as a keyboard or mouse to a PC without special drivers, including the BIOS at boot time 14 | * utilize functionality not found in the standard Keyboard/Mouse libraries on Leonardo such as consumer and system keys 15 | 16 | So far this wrapper has been developed for a specific project, but I will expand it and make it more configurable in the future. In short order I plan to integrate TMK's functionality for: 17 | * mouse keys 18 | * V-USB host implementation 19 | * PJRC host implementation (if possible) 20 | 21 | "Internal" components (such as protocols, command, bootmagic, etc) are integrated using their native C implementations. 22 | 23 | "API" components (such as hosts, matrices, and keymaps) are refactored into a C++ object heirarchy to allow for easier customization & implementation within the Arduino IDE. 24 | 25 | To get started, download this project as a zip file and put it in your Arduino libraries folder. You can use the [terminal_bluefruit_converter] (https://github.com/bgould/arduino-tmk-keyboard/blob/master/examples/terminal_bluefruit_converter/terminal_bluefruit_converter.ino) example to see an example of how to utilize this library to build a bluetooth converter for a terminal Model M keyboard. 26 | 27 | Resources: 28 | * [EZ-Key HID Tutorial at learn.adafruit.com](http://learn.adafruit.com/introducing-bluefruit-ez-key-diy-bluetooth-hid-keyboard) 29 | * [TMK Keyboard Firmware](http://github.com/tmk/tmk_keyboard) 30 | -------------------------------------------------------------------------------- /PS2MatrixCodeset3.h: -------------------------------------------------------------------------------- 1 | #ifndef PS2CODESET3KEYMAP_H 2 | #define PS2CODESET3KEYMAP_H 1 3 | 4 | #include "PS2Matrix.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | /* 11 | * IBM Terminal keyboard 6110345(122keys)/1392595(102keys) 12 | * http://geekhack.org/showthread.php?10737-What-Can-I-Do-With-a-Terminal-Model-M 13 | * http://www.seasip.info/VintagePC/ibm_1391406.html 14 | * 15 | * Keymap array: 16 | * 8 bytes 17 | * +---------+ 18 | * 0| | 19 | * :| | 0x00-0x87 20 | * ;| | 21 | * 17| | 22 | * +---------+ 23 | */ 24 | #define PS2_CODESET3_KEYMAP( \ 25 | K08,K10,K18,K20,K28,K30,K38,K40,K48,K50,K57,K5F, \ 26 | K07,K0F,K17,K1F,K27,K2F,K37,K3F,K47,K4F,K56,K5E, \ 27 | \ 28 | K05,K06, K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K5D,K66, K67,K6E,K6F, K76,K77,K7E,K84, \ 29 | K04,K0C, K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B, K5C, K64,K65,K6D, K6C,K75,K7D,K7C, \ 30 | K03,K0B, K14,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K53,K5A, K63, K6B,K73,K74,K7B, \ 31 | K83,K0A, K12,K13,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K51,K59, K61,K62,K6A, K69,K72,K7A,K79, \ 32 | K01,K09, K11, K19, K29, K39, K58, K60, K68,K70,K71,K78 \ 33 | ) { \ 34 | { KC_NO, KC_##K01, KC_NO, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07 }, \ 35 | { KC_##K08, KC_##K09, KC_##K0A, KC_##K0B, KC_##K0C, KC_##K0D, KC_##K0E, KC_##K0F }, \ 36 | { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17 }, \ 37 | { KC_##K18, KC_##K19, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D, KC_##K1E, KC_##K1F }, \ 38 | { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27 }, \ 39 | { KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_##K2E, KC_##K2F }, \ 40 | { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37 }, \ 41 | { KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D, KC_##K3E, KC_##K3F }, \ 42 | { KC_##K40, KC_##K41, KC_##K42, KC_##K43, KC_##K44, KC_##K45, KC_##K46, KC_##K47 }, \ 43 | { KC_##K48, KC_##K49, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D, KC_##K4E, KC_##K4F }, \ 44 | { KC_##K50, KC_##K51, KC_##K52, KC_##K53, KC_##K54, KC_##K55, KC_##K56, KC_##K57 }, \ 45 | { KC_##K58, KC_##K59, KC_##K5A, KC_##K5B, KC_##K5C, KC_##K5D, KC_##K5E, KC_##K5F }, \ 46 | { KC_##K60, KC_##K61, KC_##K62, KC_##K63, KC_##K64, KC_##K65, KC_##K66, KC_##K67 }, \ 47 | { KC_##K68, KC_##K69, KC_##K6A, KC_##K6B, KC_##K6C, KC_##K6D, KC_##K6E, KC_##K6F }, \ 48 | { KC_##K70, KC_##K71, KC_##K72, KC_##K73, KC_##K74, KC_##K75, KC_##K76, KC_##K77 }, \ 49 | { KC_##K78, KC_##K79, KC_##K7A, KC_##K7B, KC_##K7C, KC_##K7D, KC_##K7E, KC_NO }, \ 50 | { KC_NO, KC_NO, KC_NO, KC_##K83, KC_##K84, KC_NO, KC_NO, KC_NO, }, \ 51 | } 52 | 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | 57 | class PS2MatrixCodeset3 : public PS2Matrix 58 | { 59 | public: 60 | PS2MatrixCodeset3(); 61 | uint8_t scan(void); 62 | uint8_t getRows(); 63 | uint8_t getCols(); 64 | }; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /api/KeyboardFirmware.cpp: -------------------------------------------------------------------------------- 1 | #include "KeyboardFirmware.h" 2 | #include "gluecode.h" 3 | 4 | static uint8_t keyboard_leds(void); 5 | static void send_keyboard(report_keyboard_t *report); 6 | static void send_mouse(report_mouse_t *report); 7 | static void send_system(uint16_t data); 8 | static void send_consumer(uint16_t data); 9 | 10 | static host_driver_t _global_host_driver = { 11 | keyboard_leds, 12 | send_keyboard, 13 | send_mouse, 14 | send_system, 15 | send_consumer 16 | }; 17 | 18 | static bool _global_host_driver_set = false; 19 | 20 | extern "C" int8_t arduino_tmk_sendchar(uint8_t c) { 21 | #if DEBUG_ENABLE 22 | return Serial.write(c); 23 | #else 24 | return 0; 25 | #endif 26 | } 27 | 28 | KeyboardFirmware_::KeyboardFirmware_() 29 | { 30 | 31 | } 32 | 33 | void KeyboardFirmware_::begin(KeyboardHost &host, KeyboardMatrix &matrix) 34 | { 35 | timer_init(); 36 | 37 | _host = &host; 38 | _matrix = &matrix; 39 | _host->begin(); 40 | _matrix->begin(); 41 | 42 | if (!_global_host_driver_set) { 43 | dprint("setting global host driver\n"); 44 | host_set_driver(&_global_host_driver); 45 | } 46 | } 47 | 48 | void KeyboardFirmware_::runTask() 49 | { 50 | static matrix_row_t matrix_prev[MATRIX_ROWS]; 51 | static uint8_t led_status = 0; 52 | matrix_row_t matrix_row = 0; 53 | matrix_row_t matrix_change = 0; 54 | 55 | _matrix->scan(); 56 | for (uint8_t r = 0; r < MATRIX_ROWS; r++) { 57 | matrix_row = _matrix->getRow(r); 58 | matrix_change = matrix_row ^ matrix_prev[r]; 59 | if (matrix_change) 60 | _matrix->debugPrint(); 61 | if (_matrix->isGhostInRow(r)) { 62 | matrix_prev[r] = matrix_row; 63 | continue; 64 | } 65 | for (uint8_t c = 0; c < MATRIX_COLS; c++) { 66 | if (matrix_change & ((matrix_row_t)1<getLEDs()) { 100 | led_status = _host->getLEDs(); 101 | setLEDs(led_status); 102 | } 103 | } 104 | 105 | void KeyboardFirmware_::setLEDs(uint8_t leds) 106 | { 107 | //if (debug_keyboard) { dprint("keyboard_set_led: "); dprintf("02X"); dprintln(); } 108 | //_host->setLEDs(leds); 109 | } 110 | 111 | KeyboardHost* KeyboardFirmware_::getHost() { 112 | return _host; 113 | } 114 | 115 | KeyboardFirmware_ KeyboardFirmware; 116 | 117 | // Not implemented yet 118 | static uint8_t keyboard_leds(void) { 119 | return KeyboardFirmware.getHost()->getLEDs(); 120 | } 121 | 122 | static void send_system(uint16_t data) { 123 | KeyboardFirmware.getHost()->sendSystem(data); 124 | } 125 | 126 | static void send_keyboard(report_keyboard_t *report_t) { 127 | KeyboardReport report(report_t); 128 | KeyboardFirmware.getHost()->sendKeyboard(report); 129 | //delete &report; 130 | } 131 | 132 | static void send_mouse(report_mouse_t *report_t) { 133 | MouseReport report(report_t); 134 | KeyboardFirmware.getHost()->sendMouse(report); 135 | //delete &report; 136 | } 137 | 138 | static void send_consumer(uint16_t data) { 139 | KeyboardFirmware.getHost()->sendConsumer(data); 140 | } 141 | -------------------------------------------------------------------------------- /api/BluefruitHost.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BluefruitHost.cpp 3 | * 4 | * Copyright 2013 Benjamin Gould 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 | * MA 02110-1301, USA. 20 | * 21 | * 22 | */ 23 | 24 | // see: http://learn.adafruit.com/introducing-bluefruit-ez-key-diy-bluetooth-hid-keyboard 25 | // TODO: add logic for using software serial as well - BCG 26 | 27 | #include "BluefruitHost.h" 28 | 29 | static inline void bluefruit_trace_header() 30 | { 31 | dprint("bluefruit: "); 32 | } 33 | 34 | static inline void bluefruit_trace_footer() 35 | { 36 | dprintln(); 37 | } 38 | 39 | BluefruitHost::BluefruitHost() { 40 | } 41 | 42 | void BluefruitHost::begin() 43 | { 44 | Serial1.begin(9600); 45 | } 46 | 47 | uint8_t BluefruitHost::getLEDs() 48 | { 49 | // not implemented on Bluefruit; method is virtual so feel free to override 50 | return 0; 51 | } 52 | 53 | void BluefruitHost::sendKeyboard(KeyboardReport &report) 54 | { 55 | bluefruit_trace_header(); 56 | dprintf("(keyboard) "); 57 | _serial_send(0xFD); 58 | _serial_send(report.getModifiers()); 59 | _serial_send(report.getReserved()); 60 | for (short i = 0; i < REPORT_SIZE; i++) 61 | { 62 | _serial_send(report.getKey(i)); 63 | } 64 | bluefruit_trace_footer(); 65 | } 66 | 67 | void BluefruitHost::sendMouse(MouseReport &report) 68 | { 69 | bluefruit_trace_header(); 70 | dprintf("(mouse) "); 71 | _serial_send(0xFD); 72 | _serial_send(0x00); 73 | _serial_send(0x03); 74 | _serial_send(report.getButtons()); 75 | _serial_send(report.getX()); 76 | _serial_send(report.getY()); 77 | _serial_send(report.getV()); // TODO: determine if bluefruit 78 | _serial_send(report.getH()); // supports mouse wheel - BCG 79 | _serial_send(0x00); 80 | bluefruit_trace_footer(); 81 | }; 82 | 83 | /* 84 | +-----------------+-------------------+-------+ 85 | | Consumer Key | Bit Map | Hex | 86 | +-----------------+-------------------+-------+ 87 | | Home | 00000001 00000000 | 01 00 | 88 | | KeyboardLayout | 00000010 00000000 | 02 00 | 89 | | Search | 00000100 00000000 | 04 00 | 90 | | Snapshot | 00001000 00000000 | 08 00 | 91 | | VolumeUp | 00010000 00000000 | 10 00 | 92 | | VolumeDown | 00100000 00000000 | 20 00 | 93 | | Play/Pause | 01000000 00000000 | 40 00 | 94 | | Fast Forward | 10000000 00000000 | 80 00 | 95 | | Rewind | 00000000 00000001 | 00 01 | 96 | | Scan Next Track | 00000000 00000010 | 00 02 | 97 | | Scan Prev Track | 00000000 00000100 | 00 04 | 98 | | Random Play | 00000000 00001000 | 00 08 | 99 | | Stop | 00000000 00010000 | 00 10 | 100 | +-------------------------------------+-------+ 101 | */ 102 | #define CONSUMER2BLUEFRUIT(usage) \ 103 | (usage == AUDIO_MUTE ? 0x0000 : \ 104 | (usage == AUDIO_VOL_UP ? 0x1000 : \ 105 | (usage == AUDIO_VOL_DOWN ? 0x2000 : \ 106 | (usage == TRANSPORT_NEXT_TRACK ? 0x0002 : \ 107 | (usage == TRANSPORT_PREV_TRACK ? 0x0004 : \ 108 | (usage == TRANSPORT_STOP ? 0x0010 : \ 109 | (usage == TRANSPORT_STOP_EJECT ? 0x0000 : \ 110 | (usage == TRANSPORT_PLAY_PAUSE ? 0x4000 : \ 111 | (usage == AL_CC_CONFIG ? 0x0000 : \ 112 | (usage == AL_EMAIL ? 0x0000 : \ 113 | (usage == AL_CALCULATOR ? 0x0000 : \ 114 | (usage == AL_LOCAL_BROWSER ? 0x0000 : \ 115 | (usage == AC_SEARCH ? 0x0400 : \ 116 | (usage == AC_HOME ? 0x0100 : \ 117 | (usage == AC_BACK ? 0x0000 : \ 118 | (usage == AC_FORWARD ? 0x0000 : \ 119 | (usage == AC_STOP ? 0x0000 : \ 120 | (usage == AC_REFRESH ? 0x0000 : \ 121 | (usage == AC_BOOKMARKS ? 0x0000 : 0))))))))))))))))))) 122 | void BluefruitHost::sendConsumer(uint16_t data) 123 | { 124 | if (data == _last_consumer_data) return; 125 | _last_consumer_data = data; 126 | 127 | uint16_t bitmap = CONSUMER2BLUEFRUIT(data); 128 | bluefruit_trace_header(); 129 | dprintf("(consumer) "); 130 | _serial_send(0xFD); 131 | _serial_send(0x00); 132 | _serial_send(0x02); 133 | _serial_send((bitmap>>8)&0xFF); 134 | _serial_send(bitmap&0xFF); 135 | _serial_send(0x00); 136 | _serial_send(0x00); 137 | _serial_send(0x00); 138 | _serial_send(0x00); 139 | bluefruit_trace_footer(); 140 | }; 141 | 142 | void BluefruitHost::sendSystem(uint16_t data) 143 | { 144 | // not implemented in Bluefruit 145 | } 146 | 147 | void BluefruitHost::_serial_send(uint8_t data) 148 | { 149 | dprint(" "); 150 | dprintf("%02x", data); 151 | Serial1.write(data); 152 | } 153 | -------------------------------------------------------------------------------- /api/PS2MatrixCodeset3.cpp: -------------------------------------------------------------------------------- 1 | #include "PS2MatrixCodeset3.h" 2 | 3 | PS2MatrixCodeset3::PS2MatrixCodeset3() { 4 | } 5 | 6 | uint8_t PS2MatrixCodeset3::scan() 7 | { 8 | // scan code reading states 9 | static enum { 10 | RESET, 11 | RESET_RESPONSE, 12 | KBD_ID0, 13 | KBD_ID1, 14 | CODESET_QUERY, 15 | CODESET_RESPONSE, 16 | CODESET_REQUEST, 17 | CONFIG, 18 | READY, 19 | F0, 20 | } state = RESET; 21 | 22 | _is_modified = false; 23 | 24 | uint8_t code; 25 | if ((code = ps2_host_recv())) { 26 | dprint("r"); 27 | dprintf("%02X", code); 28 | dprint(" "); 29 | } 30 | 31 | uint8_t response; 32 | switch (state) { 33 | case RESET: 34 | dprint("wFF "); 35 | response = ps2_host_send(0xFF); 36 | if (response == 0xFA) { 37 | dprint("[ack]\nRESET_RESPONSE: "); 38 | state = RESET_RESPONSE; 39 | } else { 40 | dprint("{ response: "); 41 | dprintf("%02x", response); 42 | dprint(", error: "); 43 | dprintf("%x", ps2_error); 44 | dprint("} "); 45 | dprintln(); 46 | } 47 | break; 48 | case RESET_RESPONSE: 49 | if (code == 0xAA) { 50 | dprint("[ok]\nKBD_ID: "); 51 | state = KBD_ID0; 52 | } else if (code) { 53 | dprint("err\nRESET: "); 54 | state = RESET; 55 | } 56 | break; 57 | // after reset receive keyboard ID(2 bytes) 58 | case KBD_ID0: 59 | if (code) { 60 | state = KBD_ID1; 61 | } 62 | break; 63 | case KBD_ID1: 64 | if (code) { 65 | dprint("\nCODESET_QUERY: "); 66 | state = CODESET_QUERY; 67 | } 68 | break; 69 | case CODESET_QUERY: 70 | dprint("wF0 "); 71 | response = ps2_host_send(0xF0); 72 | if (response == 0xFA) { 73 | dprint("[ack] w00 "); 74 | response = ps2_host_send(0x00); 75 | dprint("[codeset] "); 76 | dprintf("%02X ", response); 77 | if (response == 0xFA) { 78 | dprint("[ack]\nCODESET_RESPONSE: "); 79 | state = CODESET_RESPONSE; 80 | } else { 81 | dprint("[err: "); 82 | dprintf("%02X", response); 83 | dprint("]\nRESET: "); 84 | state = RESET; 85 | } 86 | } else if (response == 0xFE) { 87 | dprint("[codeset req cmd not supported; assume ok]\nCONFIG: "); 88 | state = CONFIG; 89 | } else { 90 | dprint("[err: "); 91 | dprintf("%02X", response); 92 | dprint("]\nRESET: "); 93 | state = RESET; 94 | } 95 | break; 96 | case CODESET_RESPONSE: 97 | dprintf("%02X ", code); 98 | if (code == 0x03) { 99 | dprint("[ok]\nCONFIG: "); 100 | state = CONFIG; 101 | } else if (code == 0x02) { 102 | dprint("[ok]\nCODESET_REQUEST: "); 103 | state = CODESET_REQUEST; 104 | } else { 105 | dprint("[err]\nRESET: "); 106 | state = RESET; 107 | } 108 | break; 109 | case CODESET_REQUEST: 110 | dprint("wF0 "); 111 | response = ps2_host_send(0xF0); 112 | if (response == 0xFA) { 113 | dprint("[ack] w03 "); 114 | response = ps2_host_send(0x03); 115 | if (response == 0xFA) { 116 | dprint("[ok]\nCODESET_QUERY: "); 117 | state = CODESET_QUERY; 118 | } else { 119 | dprint("[err]\nRESET: "); 120 | state = RESET; 121 | } 122 | } else { 123 | dprint("[err]\nRESET: "); 124 | state = RESET; 125 | } 126 | break; 127 | case CONFIG: 128 | dprint("wF8 "); 129 | if (ps2_host_send(0xF8) == 0xFA) { 130 | dprint("[ack]\nREADY\n"); 131 | state = READY; 132 | } 133 | break; 134 | case READY: 135 | switch (code) { 136 | case 0x00: 137 | break; 138 | case 0xF0: 139 | state = F0; 140 | dprint(" "); 141 | break; 142 | default: // normal key make 143 | if (code < 0x88) { 144 | _make(code); 145 | } else { 146 | dprint("unexpected scan code at READY: "); 147 | dprintf("%02X", code); 148 | dprint("\n"); 149 | } 150 | state = READY; 151 | dprint("\n"); 152 | } 153 | break; 154 | case F0: // Break code 155 | switch (code) { 156 | case 0x00: 157 | break; 158 | default: 159 | if (code < 0x88) { 160 | _break(code); 161 | } else { 162 | dprint("unexpected scan code at F0: "); 163 | dprintf("%02X", code); 164 | dprint("\n"); 165 | } 166 | state = READY; 167 | dprint("\n"); 168 | } 169 | break; 170 | } 171 | return 1; 172 | } 173 | 174 | uint8_t PS2MatrixCodeset3::getRows() 175 | { 176 | return MATRIX_ROWS; 177 | } 178 | 179 | uint8_t PS2MatrixCodeset3::getCols() 180 | { 181 | return MATRIX_COLS; 182 | } 183 | -------------------------------------------------------------------------------- /examples/terminal_bluefruit_converter/terminal_bluefruit_converter.ino: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | 4 | BluefruitHost host; 5 | PS2MatrixCodeset3 matrix; 6 | static uint16_t reset_press_time = 0; 7 | 8 | void setup() { 9 | 10 | pinMode(KEY_LED_PIN, INPUT); 11 | pinMode(PAIR_LED_PIN, INPUT); 12 | pinMode(PAIR_BUTTON_PIN, OUTPUT); 13 | pinMode(RESET_BUTTON_PIN, OUTPUT); 14 | pinMode(DEBUGGING_LED, OUTPUT); 15 | 16 | digitalWrite(PAIR_BUTTON_PIN, LOW); // write high for 5 seconds to reset pairing 17 | digitalWrite(RESET_BUTTON_PIN, LOW); // pull low to reset the bluefruit module 18 | digitalWrite(OUTPUT_LED_PIN, OUTPUT_LED_OFF); 19 | 20 | #if DEBUG_ENABLE 21 | debug_enable = true; 22 | while (!Serial) ; 23 | #endif 24 | 25 | print_set_sendchar(arduino_tmk_sendchar); 26 | dprint("started logging\n"); 27 | 28 | digitalWrite(DEBUGGING_LED, DEBUGGING_LED_ON); 29 | KeyboardFirmware.begin(host, matrix); 30 | digitalWrite(DEBUGGING_LED, DEBUGGING_LED_OFF); 31 | 32 | digitalWrite(RESET_BUTTON_PIN, HIGH); // turn on bluefruit 33 | } 34 | 35 | void loop() { 36 | 37 | // this the main hook into the tmk firmware that handles all the heavy lifting 38 | KeyboardFirmware.runTask(); 39 | 40 | // Now sync the pair button light with the output pin 41 | if (digitalRead(PAIR_LED_PIN) == HIGH) { 42 | digitalWrite(OUTPUT_LED_PIN, OUTPUT_LED_ON); 43 | } else { 44 | digitalWrite(OUTPUT_LED_PIN, OUTPUT_LED_OFF); 45 | } 46 | 47 | // receive any messages from Bluefruit and output them if necessary 48 | unsigned char c; 49 | while (Serial1.available()) { 50 | c = (unsigned char) Serial1.read(); 51 | if (debug_enable) Serial.write(c); 52 | } 53 | 54 | // next we'll check if the reset key was held down for 5 seconds 55 | if (reset_press_time && timer_elapsed(reset_press_time) > 5000) { 56 | dprintf("= setting reset low\n"); 57 | digitalWrite(RESET_BUTTON_PIN, LOW); 58 | delay(10); 59 | digitalWrite(RESET_BUTTON_PIN, HIGH); 60 | dprintf("= restored reset high\n"); 61 | reset_press_time = 0; 62 | } 63 | 64 | } 65 | 66 | void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) 67 | { 68 | bool pressed = record->event.pressed; 69 | dprint("== action function called"); dprintln(); 70 | dprint("= id: "); debug_dec(id); dprintln(); 71 | dprint("= pressed: "); debug_dec(record->event.pressed); dprintln(); 72 | if (id == 0) { 73 | if (pressed) { 74 | layer_on(1); 75 | } else { 76 | layer_clear(); 77 | } 78 | } else if (id == 1) { // bluefruit pair button 79 | if (pressed) { 80 | dprintf("= setting pair button HIGH\n"); 81 | digitalWrite(PAIR_BUTTON_PIN, HIGH); 82 | } else { 83 | dprintf("= setting pair button LOW\n"); 84 | digitalWrite(PAIR_BUTTON_PIN, LOW); 85 | } 86 | } else if (id == 2) { 87 | if (pressed) { 88 | if (reset_press_time == 0) { 89 | reset_press_time = timer_read(); 90 | } 91 | } else { 92 | reset_press_time = 0; 93 | } 94 | } 95 | dprint("== end of action function\n"); 96 | } 97 | 98 | START_KEYMAPS 99 | 100 | KEYMAPS = { 101 | /* 0: default 102 | * ,---. ,---------------. ,---------------. ,---------------. ,-----------. 103 | * |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| 104 | * `---' `---------------' `---------------' `---------------' `-----------' 105 | * ,-----------------------------------------------------------. ,-----------. ,---------------. 106 | * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| \|BS | |Ins|Hom|PgU| |NmL| /| *| -| 107 | * |-----------------------------------------------------------| |-----------| |---------------| 108 | * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| | 7| 8| 9| | 109 | * |-----------------------------------------------------------| `-----------' |-----------| +| 110 | * |CapsLo| A| S| D| F| G| H| J| K| L| ;| '| #|Retu| | 4| 5| 6| | 111 | * |-----------------------------------------------------------| ,---. |---------------| 112 | * |Shif| \| Z| X| C| V| B| N| M| ,| ,| /|Shift | |Up | | 1| 2| 3| | 113 | * |-----------------------------------------------------------| ,-----------. |-----------|Ent| 114 | * |Ctrl| |Alt | Space |Alt | |Ctrl| |Lef|Dow|Rig| | 0| .| | 115 | * `----' `---------------------------------------' `----' `-----------' `---------------' 116 | */ 117 | PS2_CODESET3_KEYMAP( 118 | ESC, F14, F15, F16, F17, F18, F19, F20, F21, F22, PSCR,SLCK, 119 | F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, 120 | 121 | PSCR,ESC, GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, JYEN,BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, 122 | SLCK,INT4, TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC, BSLS, DEL, END, PGDN, P7, P8, P9, PPLS, 123 | PAUS,INT5, LCTL,A, S, D, F, G, H, J, K, L, SCLN,QUOT, NUHS,ENT, UP, P4, P5, P6, PCMM, 124 | APP, INT6, LSFT,NUBS,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RO, RSFT, LEFT,PAUS,RGHT, P1, P2, P3, PENT, 125 | RGUI,LGUI, FN0, LALT, SPC, RALT, RCTL, DOWN, NO, P0, PDOT,NO 126 | ), 127 | PS2_CODESET3_KEYMAP( 128 | TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, 129 | TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, 130 | 131 | TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, FN1, LGUI,VOLU, TRNS,TRNS,TRNS,TRNS, 132 | TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS, FN2, APP, VOLD, BTN1,MS_U,BTN2,TRNS, 133 | TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS, TRNS, MS_L,MS_D,MS_R,TRNS, 134 | TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS, TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS, 135 | TRNS,TRNS, TRNS, TRNS, TRNS, LGUI, APP, TRNS, TRNS,TRNS,TRNS,TRNS 136 | ), 137 | }; 138 | 139 | FN_ACTIONS = { 140 | ACTION_FUNCTION(0), 141 | ACTION_FUNCTION(1), 142 | ACTION_FUNCTION(2), 143 | }; 144 | 145 | KEYMAPS_FINISHED 146 | -------------------------------------------------------------------------------- /gluecode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gluecode.h 3 | * 4 | * Copyright 2014 Benjamin Gould 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 | * MA 02110-1301, USA. 20 | * 21 | * 22 | */ 23 | 24 | #ifndef TMK_GLUECODE_H 25 | #define TMK_GLUECODE_H 1 26 | 27 | #include "Arduino.h" 28 | 29 | #define NO_ACTION_MACRO 30 | #define NO_ACTION_ONESHOT 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | #ifndef DEBUG_H 37 | #define DEBUG_H 1 38 | 39 | void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t)); 40 | 41 | #if DEBUG_ENABLE 42 | 43 | #define dprint(s) do { if (debug_enable) xputs(PSTR(s)); } while (0) 44 | #define dprintln() do { if (debug_enable) xputs(PSTR("\n")); } while (0) 45 | #define dprintf(fmt, ...) do { if (debug_enable) xprintf(PSTR(fmt), ##__VA_ARGS__); } while (0) 46 | #define dmsg(s) dprintf("%s at %s: %S\n", __FILE__, __LINE__, PSTR(s)) 47 | 48 | /* for old name */ 49 | #define pdec(data) print_dec(data) 50 | #define pdec16(data) print_dec(data) 51 | #define phex(data) print_hex8(data) 52 | #define phex16(data) print_hex16(data) 53 | #define pbin(data) print_bin8(data) 54 | #define pbin16(data) print_bin16(data) 55 | #define pbin_reverse(data) print_bin_reverse8(data) 56 | #define pbin_reverse16(data) print_bin_reverse16(data) 57 | 58 | /* print value utility */ 59 | #define print_val_dec(v) dprintf(#v ": %u\n", v) 60 | #define print_val_decs(v) dprintf(#v ": %d\n", v) 61 | #define print_val_hex8(v) dprintf(#v ": %X\n", v) 62 | #define print_val_hex16(v) dprintf(#v ": %02X\n", v) 63 | #define print_val_hex32(v) dprintf(#v ": %04lX\n", v) 64 | #define print_val_bin8(v) dprintf(#v ": %08b\n", v) 65 | #define print_val_bin16(v) dprintf(#v ": %016b\n", v) 66 | #define print_val_bin32(v) dprintf(#v ": %032lb\n", v) 67 | #define print_val_bin_reverse8(v) dprintf(#v ": %08b\n", bitrev(v)) 68 | #define print_val_bin_reverse16(v) dprintf(#v ": %016b\n", bitrev16(v)) 69 | #define print_val_bin_reverse32(v) dprintf(#v ": %032lb\n", bitrev32(v)) 70 | 71 | /* print string stored in program memory(FLASH) 72 | * print_P(PSTR("hello world"); 73 | * This consumes relatively abundant FLASH memory area not SRAM. 74 | */ 75 | #define print_P(s) xputs(PSTR(s)) 76 | 77 | /* decimal */ 78 | #define print_dec(i) dprintf("%u", i) 79 | #define print_decs(i) dprintf("%d", i) 80 | 81 | /* hex */ 82 | #define print_hex4(i) dprintf("%X", i) 83 | #define print_hex8(i) dprintf("%02X", i) 84 | #define print_hex16(i) dprintf("%04X", i) 85 | #define print_hex32(i) dprintf("%08lX", i) 86 | 87 | /* binary */ 88 | #define print_bin4(i) dprintf("%04b", i) 89 | #define print_bin8(i) dprintf("%08b", i) 90 | #define print_bin16(i) dprintf("%016b", i) 91 | #define print_bin32(i) dprintf("%032lb", i) 92 | 93 | #define print_bin_reverse8(i) dprintf("%08b", bitrev(i)) 94 | #define print_bin_reverse16(i) dprintf("%016b", bitrev16(i)) 95 | #define print_bin_reverse32(i) dprintf("%032lb", bitrev32(i)) 96 | 97 | /* DO NOT USE these anymore */ 98 | #define debug(s) do { if (debug_enable) xputs(PSTR(s)); } while (0) 99 | #define debugln(s) do { if (debug_enable) xputs(PSTR("\n")); } while (0) 100 | //#define debug_S(s) do { if (debug_enable) print_S(s); } while (0) 101 | #define debug_P(s) do { if (debug_enable) print_P(s); } while (0) 102 | #define debug_msg(s) do { \ 103 | if (debug_enable) { \ 104 | print_P(__FILE__); print_P(" at "); print_dec(__LINE__); print_P(" in "); print_P(": "); print_P(s); \ 105 | } \ 106 | } while (0) 107 | #define debug_dec(data) do { if (debug_enable) print_dec(data); } while (0) 108 | #define debug_decs(data) do { if (debug_enable) print_decs(data); } while (0) 109 | #define debug_hex4(data) do { if (debug_enable) print_hex4(data); } while (0) 110 | #define debug_hex8(data) do { if (debug_enable) print_hex8(data); } while (0) 111 | #define debug_hex16(data) do { if (debug_enable) print_hex16(data); } while (0) 112 | #define debug_hex32(data) do { if (debug_enable) print_hex32(data); } while (0) 113 | #define debug_bin8(data) do { if (debug_enable) print_bin8(data); } while (0) 114 | #define debug_bin16(data) do { if (debug_enable) print_bin16(data); } while (0) 115 | #define debug_bin32(data) do { if (debug_enable) print_bin32(data); } while (0) 116 | #define debug_bin_reverse8(data) do { if (debug_enable) print_bin_reverse8(data); } while (0) 117 | #define debug_bin_reverse16(data) do { if (debug_enable) print_bin_reverse16(data); } while (0) 118 | #define debug_bin_reverse32(data) do { if (debug_enable) print_bin_reverse32(data); } while (0) 119 | #define debug_hex(data) debug_hex8(data) 120 | #define debug_bin(data) debug_bin8(data) 121 | #define debug_bin_reverse(data) debug_bin8(data) 122 | 123 | #else 124 | #include "tmk/tmk_keyboard/common/nodebug.h" 125 | 126 | #define print_S(s) 127 | #define print_P(s) 128 | #define print_dec(data) 129 | #define print_decs(data) 130 | #define print_hex4(data) 131 | #define print_hex8(data) 132 | #define print_hex16(data) 133 | #define print_hex32(data) 134 | #define print_bin4(data) 135 | #define print_bin8(data) 136 | #define print_bin16(data) 137 | #define print_bin32(data) 138 | #define print_bin_reverse8(data) 139 | #define print_bin_reverse16(data) 140 | #define print_bin_reverse32(data) 141 | 142 | #endif 143 | 144 | #endif 145 | 146 | #ifndef NODEBUG_H 147 | #define NODEBUG_H 1 148 | #endif 149 | 150 | #include "tmk/xprintf.h" 151 | #include "tmk/tmk_keyboard/common/debug_config.h" 152 | #include "tmk/tmk_keyboard/common/keymap.h" 153 | #include "tmk/tmk_keyboard/protocol/ps2.h" 154 | #include "tmk/tmk_keyboard/common/report.h" 155 | #include "tmk/tmk_keyboard/common/matrix.h" 156 | #include "tmk/tmk_keyboard/common/action.h" 157 | #include "tmk/tmk_keyboard/common/action_layer.h" 158 | #include "tmk/tmk_keyboard/common/util.h" 159 | #include "tmk/tmk_keyboard/common/host.h" 160 | #include "tmk/tmk_keyboard/common/timer.h" 161 | #include "tmk/tmk_keyboard/common/command.h" 162 | 163 | #if MOUSEKEY_ENABLE 164 | #include "tmk/tmk_keyboard/common/mousekey.h" 165 | #endif 166 | 167 | int8_t arduino_tmk_sendchar(uint8_t c); 168 | 169 | void exec_action(uint8_t r, uint8_t c, matrix_row_t matrix_row); 170 | 171 | 172 | #ifdef __cplusplus 173 | } 174 | #endif 175 | 176 | #endif 177 | -------------------------------------------------------------------------------- /tmk/xprintf.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------/ 2 | / Universal string handler for user console interface 3 | /-------------------------------------------------------------------------/ 4 | / 5 | / Copyright (C) 2011, ChaN, all right reserved. 6 | / 7 | / * This software is a free software and there is NO WARRANTY. 8 | / * No restriction on use. You can use, modify and redistribute it for 9 | / personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. 10 | / * Redistributions of source code must retain the above copyright notice. 11 | / 12 | /-------------------------------------------------------------------------*/ 13 | 14 | #include "xprintf.h" 15 | 16 | 17 | #if _USE_XFUNC_OUT 18 | #include 19 | void (*xfunc_out)(unsigned char); /* Pointer to the output stream */ 20 | static char *outptr; 21 | 22 | /*----------------------------------------------*/ 23 | /* Put a character */ 24 | /*----------------------------------------------*/ 25 | 26 | void xputc (char c) 27 | { 28 | if (_CR_CRLF && c == '\n') xputc('\r'); /* CR -> CRLF */ 29 | 30 | if (outptr) { 31 | *outptr++ = (unsigned char)c; 32 | return; 33 | } 34 | 35 | if (xfunc_out) xfunc_out((unsigned char)c); 36 | } 37 | 38 | 39 | 40 | /*----------------------------------------------*/ 41 | /* Put a null-terminated string */ 42 | /*----------------------------------------------*/ 43 | 44 | void xputs ( /* Put a string to the default device */ 45 | const char* str /* Pointer to the string */ 46 | ) 47 | { 48 | unsigned char c; 49 | do { 50 | c = pgm_read_byte(str++); 51 | if (c) 52 | xputc(c); 53 | } while (c); 54 | } 55 | 56 | 57 | void xfputs ( /* Put a string to the specified device */ 58 | void(*func)(unsigned char), /* Pointer to the output function */ 59 | const char* str /* Pointer to the string */ 60 | ) 61 | { 62 | void (*pf)(unsigned char); 63 | 64 | 65 | pf = xfunc_out; /* Save current output device */ 66 | xfunc_out = func; /* Switch output to specified device */ 67 | unsigned char c; 68 | do { 69 | c = pgm_read_byte(str++); 70 | if (c) 71 | xputc(c); 72 | } while (c); 73 | xfunc_out = pf; /* Restore output device */ 74 | } 75 | 76 | 77 | 78 | /*----------------------------------------------*/ 79 | /* Formatted string output */ 80 | /*----------------------------------------------*/ 81 | /* xprintf("%d", 1234); "1234" 82 | xprintf("%6d,%3d%%", -200, 5); " -200, 5%" 83 | xprintf("%-6u", 100); "100 " 84 | xprintf("%ld", 12345678L); "12345678" 85 | xprintf("%04x", 0xA3); "00a3" 86 | xprintf("%08LX", 0x123ABC); "00123ABC" 87 | xprintf("%016b", 0x550F); "0101010100001111" 88 | xprintf("%s", "String"); "String" 89 | xprintf("%-4s", "abc"); "abc " 90 | xprintf("%4s", "abc"); " abc" 91 | xprintf("%c", 'a'); "a" 92 | xprintf("%f", 10.0); 93 | */ 94 | 95 | static 96 | void xvprintf ( 97 | const char* fmt, /* Pointer to the format string */ 98 | va_list arp /* Pointer to arguments */ 99 | ) 100 | { 101 | unsigned int r, i, j, w, f; 102 | unsigned long v; 103 | char s[16], c, d, *p; 104 | 105 | 106 | for (;;) { 107 | c = pgm_read_byte(fmt++); /* Get a char */ 108 | if (!c) break; /* End of format? */ 109 | if (c != '%') { /* Pass through it if not a % sequense */ 110 | xputc(c); continue; 111 | } 112 | f = 0; 113 | c = pgm_read_byte(fmt++); /* Get first char of the sequense */ 114 | if (c == '0') { /* Flag: '0' padded */ 115 | f = 1; c = pgm_read_byte(fmt++); 116 | } else { 117 | if (c == '-') { /* Flag: left justified */ 118 | f = 2; c = pgm_read_byte(fmt++); 119 | } 120 | } 121 | for (w = 0; c >= '0' && c <= '9'; c = pgm_read_byte(fmt++)) /* Minimum width */ 122 | w = w * 10 + c - '0'; 123 | if (c == 'l' || c == 'L') { /* Prefix: Size is long int */ 124 | f |= 4; c = pgm_read_byte(fmt++); 125 | } 126 | if (!c) break; /* End of format? */ 127 | d = c; 128 | if (d >= 'a') d -= 0x20; 129 | switch (d) { /* Type is... */ 130 | case 'S' : /* String */ 131 | p = va_arg(arp, char*); 132 | for (j = 0; p[j]; j++) ; 133 | while (!(f & 2) && j++ < w) xputc(' '); 134 | xputs(p); 135 | while (j++ < w) xputc(' '); 136 | continue; 137 | case 'C' : /* Character */ 138 | xputc((char)va_arg(arp, int)); continue; 139 | case 'B' : /* Binary */ 140 | r = 2; break; 141 | case 'O' : /* Octal */ 142 | r = 8; break; 143 | case 'D' : /* Signed decimal */ 144 | case 'U' : /* Unsigned decimal */ 145 | r = 10; break; 146 | case 'X' : /* Hexdecimal */ 147 | r = 16; break; 148 | default: /* Unknown type (passthrough) */ 149 | xputc(c); continue; 150 | } 151 | 152 | /* Get an argument and put it in numeral */ 153 | v = (f & 4) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : (long)va_arg(arp, unsigned int)); 154 | if (d == 'D' && (v & 0x80000000)) { 155 | v = 0 - v; 156 | f |= 8; 157 | } 158 | i = 0; 159 | do { 160 | d = (char)(v % r); v /= r; 161 | if (d > 9) d += (c == 'x') ? 0x27 : 0x07; 162 | s[i++] = d + '0'; 163 | } while (v && i < sizeof(s)); 164 | if (f & 8) s[i++] = '-'; 165 | j = i; d = (f & 1) ? '0' : ' '; 166 | while (!(f & 2) && j++ < w) xputc(d); 167 | do xputc(s[--i]); while(i); 168 | while (j++ < w) xputc(' '); 169 | } 170 | } 171 | 172 | 173 | void xprintf ( /* Put a formatted string to the default device */ 174 | const char* fmt, /* Pointer to the format string */ 175 | ... /* Optional arguments */ 176 | ) 177 | { 178 | va_list arp; 179 | 180 | 181 | va_start(arp, fmt); 182 | xvprintf(fmt, arp); 183 | va_end(arp); 184 | } 185 | 186 | 187 | void xsprintf ( /* Put a formatted string to the memory */ 188 | char* buff, /* Pointer to the output buffer */ 189 | const char* fmt, /* Pointer to the format string */ 190 | ... /* Optional arguments */ 191 | ) 192 | { 193 | va_list arp; 194 | 195 | 196 | outptr = buff; /* Switch destination for memory */ 197 | 198 | va_start(arp, fmt); 199 | xvprintf(fmt, arp); 200 | va_end(arp); 201 | 202 | *outptr = 0; /* Terminate output string with a \0 */ 203 | outptr = 0; /* Switch destination for device */ 204 | } 205 | 206 | 207 | void xfprintf ( /* Put a formatted string to the specified device */ 208 | void(*func)(unsigned char), /* Pointer to the output function */ 209 | const char* fmt, /* Pointer to the format string */ 210 | ... /* Optional arguments */ 211 | ) 212 | { 213 | va_list arp; 214 | void (*pf)(unsigned char); 215 | 216 | 217 | pf = xfunc_out; /* Save current output device */ 218 | xfunc_out = func; /* Switch output to specified device */ 219 | 220 | va_start(arp, fmt); 221 | xvprintf(fmt, arp); 222 | va_end(arp); 223 | 224 | xfunc_out = pf; /* Restore output device */ 225 | } 226 | 227 | 228 | 229 | /*----------------------------------------------*/ 230 | /* Dump a line of binary dump */ 231 | /*----------------------------------------------*/ 232 | 233 | void put_dump ( 234 | const void* buff, /* Pointer to the array to be dumped */ 235 | unsigned long addr, /* Heading address value */ 236 | int len, /* Number of items to be dumped */ 237 | int width /* Size of the items (DF_CHAR, DF_SHORT, DF_LONG) */ 238 | ) 239 | { 240 | int i; 241 | const unsigned char *bp; 242 | const unsigned short *sp; 243 | const unsigned long *lp; 244 | 245 | 246 | xprintf("%08lX ", addr); /* address */ 247 | 248 | switch (width) { 249 | case DW_CHAR: 250 | bp = buff; 251 | for (i = 0; i < len; i++) /* Hexdecimal dump */ 252 | xprintf(" %02X", bp[i]); 253 | xputc(' '); 254 | for (i = 0; i < len; i++) /* ASCII dump */ 255 | xputc((bp[i] >= ' ' && bp[i] <= '~') ? bp[i] : '.'); 256 | break; 257 | case DW_SHORT: 258 | sp = buff; 259 | do /* Hexdecimal dump */ 260 | xprintf(" %04X", *sp++); 261 | while (--len); 262 | break; 263 | case DW_LONG: 264 | lp = buff; 265 | do /* Hexdecimal dump */ 266 | xprintf(" %08LX", *lp++); 267 | while (--len); 268 | break; 269 | } 270 | 271 | xputc('\n'); 272 | } 273 | 274 | #endif /* _USE_XFUNC_OUT */ 275 | 276 | 277 | 278 | #if _USE_XFUNC_IN 279 | unsigned char (*xfunc_in)(void); /* Pointer to the input stream */ 280 | 281 | /*----------------------------------------------*/ 282 | /* Get a line from the input */ 283 | /*----------------------------------------------*/ 284 | 285 | int xgets ( /* 0:End of stream, 1:A line arrived */ 286 | char* buff, /* Pointer to the buffer */ 287 | int len /* Buffer length */ 288 | ) 289 | { 290 | int c, i; 291 | 292 | 293 | if (!xfunc_in) return 0; /* No input function specified */ 294 | 295 | i = 0; 296 | for (;;) { 297 | c = xfunc_in(); /* Get a char from the incoming stream */ 298 | if (!c) return 0; /* End of stream? */ 299 | if (c == '\r') break; /* End of line? */ 300 | if (c == '\b' && i) { /* Back space? */ 301 | i--; 302 | if (_LINE_ECHO) xputc(c); 303 | continue; 304 | } 305 | if (c >= ' ' && i < len - 1) { /* Visible chars */ 306 | buff[i++] = c; 307 | if (_LINE_ECHO) xputc(c); 308 | } 309 | } 310 | buff[i] = 0; /* Terminate with a \0 */ 311 | if (_LINE_ECHO) xputc('\n'); 312 | return 1; 313 | } 314 | 315 | 316 | int xfgets ( /* 0:End of stream, 1:A line arrived */ 317 | unsigned char (*func)(void), /* Pointer to the input stream function */ 318 | char* buff, /* Pointer to the buffer */ 319 | int len /* Buffer length */ 320 | ) 321 | { 322 | unsigned char (*pf)(void); 323 | int n; 324 | 325 | 326 | pf = xfunc_in; /* Save current input device */ 327 | xfunc_in = func; /* Switch input to specified device */ 328 | n = xgets(buff, len); /* Get a line */ 329 | xfunc_in = pf; /* Restore input device */ 330 | 331 | return n; 332 | } 333 | 334 | 335 | /*----------------------------------------------*/ 336 | /* Get a value of the string */ 337 | /*----------------------------------------------*/ 338 | /* "123 -5 0x3ff 0b1111 0377 w " 339 | ^ 1st call returns 123 and next ptr 340 | ^ 2nd call returns -5 and next ptr 341 | ^ 3rd call returns 1023 and next ptr 342 | ^ 4th call returns 15 and next ptr 343 | ^ 5th call returns 255 and next ptr 344 | ^ 6th call fails and returns 0 345 | */ 346 | 347 | int xatoi ( /* 0:Failed, 1:Successful */ 348 | char **str, /* Pointer to pointer to the string */ 349 | long *res /* Pointer to the valiable to store the value */ 350 | ) 351 | { 352 | unsigned long val; 353 | unsigned char c, r, s = 0; 354 | 355 | 356 | *res = 0; 357 | 358 | while ((c = **str) == ' ') (*str)++; /* Skip leading spaces */ 359 | 360 | if (c == '-') { /* negative? */ 361 | s = 1; 362 | c = *(++(*str)); 363 | } 364 | 365 | if (c == '0') { 366 | c = *(++(*str)); 367 | switch (c) { 368 | case 'x': /* hexdecimal */ 369 | r = 16; c = *(++(*str)); 370 | break; 371 | case 'b': /* binary */ 372 | r = 2; c = *(++(*str)); 373 | break; 374 | default: 375 | if (c <= ' ') return 1; /* single zero */ 376 | if (c < '0' || c > '9') return 0; /* invalid char */ 377 | r = 8; /* octal */ 378 | } 379 | } else { 380 | if (c < '0' || c > '9') return 0; /* EOL or invalid char */ 381 | r = 10; /* decimal */ 382 | } 383 | 384 | val = 0; 385 | while (c > ' ') { 386 | if (c >= 'a') c -= 0x20; 387 | c -= '0'; 388 | if (c >= 17) { 389 | c -= 7; 390 | if (c <= 9) return 0; /* invalid char */ 391 | } 392 | if (c >= r) return 0; /* invalid char for current radix */ 393 | val = val * r + c; 394 | c = *(++(*str)); 395 | } 396 | if (s) val = 0 - val; /* apply sign if needed */ 397 | 398 | *res = val; 399 | return 1; 400 | } 401 | 402 | #endif /* _USE_XFUNC_IN */ 403 | --------------------------------------------------------------------------------