-
Entry for HAD 2016 prize, Phase 4: Automation
07/11/2016 at 20:57 • 0 commentsI've decided to apply this project to phase 4 of Hackaday 2016 prize which involves automation. This post is to clarify/complete some information required;
About the challenge:The project was conceived for playing "GTA" game series in a PC computer by automate the entry of cheat codes composed by single keystrokes.
About the licenses/permissions:
The project is released underGPL 2.0.
About Third party licences/restrictions
The project is based on Digi-Spark board.
Copyright of information used on the article.
"Oh Sh*t!" game was property of Aackosoft International B.V. (now extinct)
"MSX" is a trademark fromASCII Corporation
"GTA San Andreas" is a trademark from Rockstar
-
Video: Oh Cheat! in Action
02/09/2016 at 17:50 • 0 commentsHere you are a small video of Oh Cheat! in action playing GTA San Andreas.
-
Usinga a Chinese Digispark Clone
02/06/2016 at 11:33 • 0 commentsThe Chinese Digispark clones are very cheap and have a female USB connector which is good but they ship with RESET enabled which means that PB5 is not available for use.
To perform the change it is necessary to change the HFuse configuration of the ATTiny85.
I have used AVeRCADE with USBasp firmware for doing that, but any ISP programmer will do fine. The connections to a 10 pin are show below. However it is possible to use other methods, for example using an Arduino (link).
The command for programming the High fuse to its correct configuration is:avrdude -c usbasp -p t85 -U hfuse:w:0x5f:m
If everything works fine you should see something like that -
Standalone board design
01/28/2016 at 17:24 • 0 commentsI've created a standalone design for the board, single sided and using only pth components.
-
Extended Digispark Keyboard library
01/25/2016 at 23:37 • 3 commentsI've made an extension to the SendKeyStroke method of DigiKeyboard.h by adding a key down time parameter.
SendKeyStroke method now has a third parameter to allow the simulation of pressing time (in milliseconds) that the key remains pressed until is released.
void sendKeyStroke(byte keyStroke, byte modifiers, uint16_t key_down_time);
If 'key_down_time' is zero then don't release the key, it should be done manually by sendKeysStroke(0). As 'zero' means forever, the minimum press time time is 1ms and the maximum is 65535ms.
Examples:
DigiKeyboard.sendKeyStroke(KEY_B); // Send a B to host DigiKeyboard.sendKeyStroke(KEY_A,0,300); // Send an A to host, takes 300ms until release DigiKeyboard.sendKeyStroke(KEY_C,0,0); //Send a C to host and keep it pushed DigiKeyboard.delay(2000); // wait 2 seconds DigiKeyboard.sendKeyStroke(0); // now release any key pressed.
Tried to send a pull request to original project but without success, though. Either way the extended function is below:
void sendKeyStroke(byte keyStroke, byte modifiers, uint16_t key_down_time) { while (!usbInterruptIsReady()) { // Note: We wait until we can send keystroke // so we know the previous keystroke was // sent. usbPoll(); _delay_ms(5); } memset(reportBuffer, 0, sizeof(reportBuffer)); reportBuffer[0] = modifiers; reportBuffer[1] = keyStroke; usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); while (!usbInterruptIsReady()) { // Note: We wait until we can send keystroke // so we know the previous keystroke was // sent. usbPoll(); _delay_ms(5); } // Pressing time (in milliseconds) that the key remains pressed // until is released. If is zero don't release the key (it should be // done manually by sendKeysStroke(0). Therefore minimum time is 1ms // and the maximum is 65535ms. if (key_down_time) { while (key_down_time--) { usbPoll(); _delay_ms(1); } // Now send 'no key' pressed memset(reportBuffer, 0, sizeof(reportBuffer)); usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); } }
-
Busted!
01/22/2016 at 15:50 • 0 commentsI have found the problem with GTA: The game kinda sample the keyboard state, so if the key remain pressed for a few time it won't be recognized. I got that insight when I realized that sometimes the game recognized one of the keys (like A that makes the character move left).
By analyzing Digispark.h I have noticed that the SendKeyStroke function sends a key up right after the key pressed.
void sendKeyStroke(byte keyStroke, byte modifiers) { while (!usbInterruptIsReady()) { usbPoll(); _delay_ms(5); } memset(reportBuffer, 0, sizeof(reportBuffer)); reportBuffer[0] = modifiers; reportBuffer[1] = keyStroke; usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); while (!usbInterruptIsReady()) { usbPoll(); _delay_ms(5); } /* HERE WAS THE PROBLEM WITH GTA */ // This stops endlessly repeating keystrokes: memset(reportBuffer, 0, sizeof(reportBuffer)); usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); }
To solve that without messing with the Digispark routines I have simply copied the code into my sketch and ripped off the last two lines of code that send the zero (no key).The compiler complained about a missing definition of reportBuffer variable. Strangely enough the definition of such variable is not defined on DigiKeyboard.h. (it is defined in DigiMouse.h and DigiJoystick.h though!).
To fix it I have just created the variable and it compiled (and worked as well).
//////////////////////////////////////////////// // __ __ _ _ _ // \ \ / /_ _ _ _(_)__ _| |__| |___ ___ // \ V / _` | '_| / _` | '_ \ / -_|_-< // \_/\__,_|_| |_\__,_|_.__/_\___/__/ // uint8_t ticks = 0; uint8_t lastkey = 0; uint8_t temp, key; uchar reportBuffer[2];
I have also added a custom 'print' function that for each character sent to host it waits a small delay and then sends a zero (no press).// Print a string to the host, and add a key up after a delay void DigiKeyboard_print ( char *str ) { uint8_t data; while (*str) { data = pgm_read_byte_near(ascii_to_scan_code_table + (*str++ - 8)); sendKeyStroke_nostop(data & 0b01111111, data >> 7 ? MOD_SHIFT_RIGHT : 0); DigiKeyboard.delay(50); sendKeyStroke_nostop(0,0); } }
I have fiddled with this delay and found that 20ms is not enough but 50ms is fine.Bug Busted!!
-
Oh Sh**t, it's not working!
01/21/2016 at 13:35 • 0 commentsI still haven't figured out why do the game (GTASA) is not accepting the keystrokes, though it can really recognize some of the strokes.
I wrote my own 'print' method to put each key, then a zero but not worked. Then I've inserted a delay between keystrokes, and yet is not working. Even tried to send several zeros in between each keystroke but still no success.
void my_DigiKeyboard_print ( char *str ) { uint8_t data; while (*str) { data = pgm_read_byte_near(ascii_to_scan_code_table + (*str++ - 8)); DigiKeyboard.sendKeyStroke(data & 0b01111111, data >> 7 ? MOD_SHIFT_RIGHT : 0); DigiKeyboard.sendKeyStroke(0); DigiKeyboard.sendKeyStroke(0); DigiKeyboard.sendKeyStroke(0); DigiKeyboard.delay(100); } }
In any other application the keys are correctly injected, it is weird.. I still have more work to do.
-
Prototype
01/21/2016 at 03:16 • 0 commentsFor development of the firmware I have used a protoboard
I don't have a DigiSpark here but I have a DIY clone (named Cricket)
After I have built a keyboard with tactile switches. Sadly the perfboard only have room for 6 keys but nevermind, I don't give a cheat about 7th key.