/*********************************************************************** * * 254/395 V A L V E S * HID Keyboard for ZDSimulator * * with the Arduino Leonardo (Arduino Pro Micro) * **********************************************************************/ #include <Keyboard.h> /*-------------------------------------------------------- "THE BEER-WARE LICENSE" (Revision 42): Alex Kostyuk wrote this code. As long as you retain this notice you can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return. ----------------------------------------------------------*/ /* Dirty hack is needed in file <installation_folder>\Arduino\libraries\Keyboard\src\Keyboard.cpp ////////////////////////////// // Before ////////////////////////////// #define SHIFT 0x80 const uint8_t _asciimap[128] = { 0x00, // NUL 0x00, // SOH 0x00, // STX 0x00, // ETX 0x00, // EOT 0x00, // ENQ 0x00, // ACK 0x00, // BEL ////////////////////////////// // After ////////////////////////////// #define SHIFT 0x80 const uint8_t _asciimap[128] = { 0x00, // NUL 0x65, // (VK_APPS) 0x01 0x2D, // - (VK_OEM_MINUS) 0x02 0x2E, // + (VK_OEM_PLUS) 0x03 0x31, // | (VK_OEM_5) 0x04 0x2A, // BS (VK_BACK) 0x05 0x00, // ACK 0x00, // BEL Codes taken from http://www.usb.org/developers/hidpage/Hut1_12v2.pdf Table 12: Keyboard/Keypad Page 0x65, // (VK_APPS) 0x01 0x65 is a code we need to send to make the Windows to issue the VK_APPS keyboard event. VK_APPS - event code in Windows when the code 0x65 sent by USB HID. 0x01 is a code (index) which Keyboard.press(code)/Keyboard.release(code) eats to translate in 0x65. */ #define KEY_APPLICATION_MENU 0x01 #define FIFO_SIZE 16 typedef struct { int push_indx; int pop_indx; unsigned char buff[FIFO_SIZE]; } SIMPLE_FIFO; SIMPLE_FIFO fifo; char fifo_push(SIMPLE_FIFO *fifo, unsigned char data); char fifo_pop(SIMPLE_FIFO *fifo, unsigned char *data); void fifo_init(SIMPLE_FIFO *fifo); void keyboard_state_machine(void); void setup() { bits_init(); fifo_init(&fifo); Keyboard.begin(); pinMode(13, OUTPUT); } void loop(void) { discrete_task(); keyboard_state_machine(); } //------------------------------------------- // Discrete task //------------------------------------------- #define BITS_MAXIMUM 14 /*ITEMS_MAX*/ int shift = 0; #define FLAG_INVERTED (1<<0) #define FLAG_ENABLED (1<<1) enum { PUSH_BUTTON = 0, TOGGLE_SWITCH, ROTARY_SWITCH_POS, ENCODER_A, ENCODER_B, SHIFT }; typedef struct { int counter; char signal; int max; char evcode; char flag; char mode; char pin; char key_macros[6]; } BITS_DESCRIPTION; BITS_DESCRIPTION bits[BITS_MAXIMUM]; #define input_init(x,y,z,m,km) do {\ bits[x].counter = 0;\ bits[x].signal = 0;\ bits[x].max = y;\ bits[x].flag = (FLAG_ENABLED | FLAG_INVERTED);\ bits[x].pin = z;\ pinMode(z,INPUT_PULLUP);\ bits[x].mode = m;\ strcpy(bits[x].key_macros,km);\ } while(0) void bits_init(void) { int i; memset(bits,0,sizeof(bits)); #define DEBOUNCE_DELAY 100 input_init(0,DEBOUNCE_DELAY,2, ROTARY_SWITCH_POS, "\x01\x31"); input_init(1,DEBOUNCE_DELAY,3, ROTARY_SWITCH_POS, "\x01\x32"); input_init(2,DEBOUNCE_DELAY,4, ROTARY_SWITCH_POS, "\x01\x33"); input_init(3,DEBOUNCE_DELAY,5, ROTARY_SWITCH_POS, "\x01\x34"); input_init(4,DEBOUNCE_DELAY,A0, ROTARY_SWITCH_POS, "\x01\x37"); input_init(5,DEBOUNCE_DELAY,A1, ROTARY_SWITCH_POS, "\x01\x38"); input_init(6,DEBOUNCE_DELAY,A2, ROTARY_SWITCH_POS, "\x01\x39"); input_init(7,DEBOUNCE_DELAY,6, PUSH_BUTTON, "["); input_init(8,DEBOUNCE_DELAY,7, ROTARY_SWITCH_POS,"\x01\x30"); input_init(9,DEBOUNCE_DELAY,8, ROTARY_SWITCH_POS,"\x01\x02"); input_init(10,DEBOUNCE_DELAY,9, ROTARY_SWITCH_POS,"\x01\x03"); input_init(11,DEBOUNCE_DELAY,10, ROTARY_SWITCH_POS,"\x01\x04"); input_init(12,DEBOUNCE_DELAY,11, ROTARY_SWITCH_POS,"\x01\x05"); input_init(13,DEBOUNCE_DELAY,12, ROTARY_SWITCH_POS,"\x01\x05"); } void discrete_task( void) { int bit,flag; int bit_state; int i; static int pos_254_prev = 0; static int pos_395_prev = 0; static char ini_flag = 0; unsigned char *p,inc_sym; if(ini_flag == 0) { for(i=0; i<7; i++) { if(digitalRead(bits[i].pin) == 0) pos_395_prev = i; } for(; i<14; i++) { if(digitalRead(bits[i].pin) == 0) pos_254_prev = i; } ini_flag = 1; } for(i=0; i<BITS_MAXIMUM; i++) { if(bits[i].flag & FLAG_ENABLED) { bit_state = digitalRead(bits[i].pin); flag = bits[i].flag; bit = (flag & FLAG_INVERTED) ^ bit_state; if(bit) { if(bits[i].counter < bits[i].max) { if(++(bits[i].counter) >= bits[i].max) { if(bits[i].signal == 0) { //front __0__/--1-- switch(bits[i].mode) { case PUSH_BUTTON: if(i>=0 && i<=6) { pos_395_prev = i; } if(i>=7 && i<=13) { pos_254_prev = i; } p = bits[i].key_macros; while(*p) { Keyboard.press(*p++); } break; case ROTARY_SWITCH_POS: if(i>=0 && i<=6) { if(pos_395_prev < i) { inc_sym = '\''; } else if(pos_395_prev > i) { inc_sym = ';'; } pos_395_prev = i; if(i == 3 || i == 4 ) { fifo_push(&fifo, inc_sym); break; } } if(i>=7 && i<=13) { if(pos_254_prev < i) { inc_sym = ']'; } else if(pos_254_prev > i) { inc_sym = '['; } pos_254_prev = i; if(i == 11 ) { fifo_push(&fifo, inc_sym); break; } } p = bits[i].key_macros; while(*p) { fifo_push(&fifo, *p++); } break; } bits[i].signal = 1; } } } } else { if(bits[i].counter > 0) { if(--(bits[i].counter) <= 0) { if(bits[i].signal) { // edge --1--\___0___ switch(bits[i].mode) { case PUSH_BUTTON: Keyboard.releaseAll(); break; } bits[i].signal = 0; } } } } } } } enum { KE_IDLE = 0, KE_COLLECT_MACROS, KE_SHIFT_DELAY, KE_KEY_DELAY }; char is_shift_key(unsigned char key) { switch(key) { case KEY_APPLICATION_MENU: return 1; } return 0; } void keyboard_state_machine(void) { static char state = KE_COLLECT_MACROS; static int timer; unsigned char key; switch(state) { case KE_COLLECT_MACROS: digitalWrite(13, LOW); if(fifo_pop(&fifo, &key)) { if(!is_shift_key(key)) { timer = 750; state = KE_KEY_DELAY; digitalWrite(13, HIGH); Keyboard.press(key); } else { timer =350; state = KE_SHIFT_DELAY; Keyboard.press(key); } } break; case KE_SHIFT_DELAY: if(timer) { if(--timer == 0) { state = KE_COLLECT_MACROS; } } break; case KE_KEY_DELAY: if(timer) { if(--timer == 0) { Keyboard.releaseAll(); state = KE_COLLECT_MACROS; } } break; } } void fifo_init(SIMPLE_FIFO *fifo) { fifo->push_indx = 0; fifo->pop_indx = 0; } char fifo_push(SIMPLE_FIFO *fifo, unsigned char data) { int indx; indx = fifo->push_indx + 1; indx = indx % FIFO_SIZE; if (indx == fifo->pop_indx) return 0; // full fifo->buff[indx] = data; fifo->push_indx = indx; return 1; } char fifo_pop(SIMPLE_FIFO *fifo, unsigned char *data) { int indx; if (fifo->push_indx == fifo->pop_indx) return 0; // empty indx = fifo->pop_indx + 1; indx = indx % FIFO_SIZE; *data = fifo->buff[indx]; fifo->pop_indx = indx; return 1; }