Saturday 27 July 2013

New enclosures

On Thursday I've received enclosures with custom logo. Looks exactly as expected:


There is only one problem: even though all enclosures of this kind looks exactly the same on the outside, on the inside all (that I have) are different (other two are from disassembled USB flash drives).


First one from the left is the one that I've ordered. Now, if you take a look at the latest PCB revision:


it obviously won't fit in there, since it was designed basing on the first enclosure form the right (blue one). Fortunately it's not a big deal. For now, I will just remove parts of the enclosure marked by red arrows, so as a result I will get something similar to the enclosure in the middle. Next PCB revision will obviously be redesigned to fit, without having to cut out anything.

Saturday 13 July 2013

Standard devices: overview

Here is a short overview of classes that can be directly used in Android applications to emulate most common USB devices: keyboard, mouse, gamepad, consumer control:

USBDevice
Base class for any USB device that is emulated using InputStick.

Public methods:

void connect();
Description: initiates connection to InputStick device.

void disconnect();.
Description: terminates connection.

int getState();
Description: returns current connection state:
STATE_NONE - not connected.
STATE_CONNECTING - InputStickUtility is trying to connect to InputStick device.
STATE_CONNECTED - Bluetooth connection has been established.
STATE_READY - USB host has successfully enumerated InputStick device.

void registerListener(USBDeviceListener listener);
Description: registers new listener, which will be notified when connection state changes or when USB host sends data.

void unregisterListener(USBDeviceListener listener);
Description: removes listener, it will no longer receive notifications.

void setContext(Context context);
Description: sets context. Must be called before initiating connection!

 
USBDeviceListener
Interface that must be implemented by a class that wants to be able to receive callbacks when connections state changes or data form USB host is received.

Public methods:

void onUSBData(int endpoint, byte[] data);
Description: called when data form USB host has been received on given endpoint.

void onStateChanged(int state);.
Description: called when connection state changes.

 
USBKeyobard
Generic USB keyboard. It is assumed that USB host uses EN-US keyboard layout (or compatible, example: Polish Programmers).

Public methods:

void type(String text);
Description: types content of text. All non-ASCII characters will be ignored.

void typeUnicodeWindows(String text);
Description: types content of text using Alt Codes. This should allow to type all ASCII characters correctly, regardless of keyboard layout.  All non-ASCII characters will be ignored. Windows only!

void typeUnicodeLinux(String text);
Description: types content of text using hex code. This should allow to type all ASCII characters correctly, regardless of keyboard layout.  All non-ASCII characters will be ignored. Linux only!

void pressAndRelease(byte modifier, byte key);.
Description: first presses modifier keys (Ctrl, Alt, Shift, GUI), then presses key, finally releases all keys.
Modifiers:
ALT_LEFT - left Alt key.
CTRL_LEFT - left Ctrl key.
(...)
Keys:
KEY_A - key "a".
(...)

void delayKeyboard(int duration);
Description: waits at least duration milliseconds (not guaranteed to be precise, may be a few milliseconds longer) before sending next keyboard reports.

void sendKeyboardReport(byte modifier, byte key0, byte key1, byte key2, byte key3, byte key4, byte key5);
Description: sends custom USB keyboard report containing data specified by parameters. Does not change state of the object!

void setNumLock(boolean enable);
Description: sets state of NumLock (disabled/enabled).

void setCapsLock(boolean enable);
Description: sets state of CapsLock (disabled/enabled).

void setScrollLock(boolean enable);
Description: sets state of ScrollLock (disabled/enabled).

boolean isNumLock();
Description: returns state of NumLock.

boolean isCapsLock();
Description: returns state of CapsLock.

boolean isScrollLock();
Description: returns state of ScrollLock.

int getKeyboardProtocol();
Description: returns value of protocol set by USB host.
PROTOCOL_BOOT - for simplified boot protocol.
PROTOCOL_REPORT  - for report protocol.

 
USBMouse
Generic USB mouse: three buttons and vertical scroll wheel (scroll is not available when BOOT protocol is used).

Public methods:

void move(int x, int y);
Description: moves mouse pointer by x and y.

void scroll(int scroll);
Description: moves scroll wheel by scroll. Works only if USB host has set protocol to report protocol.

void click(int button, int duration);.
Description: presses button and releases after duration milliseconds.
BUTTON_LEFT - left mouse button.
BUTTON_RIGHT - right mouse button.
BUTTON_MIDDLE - middle mouse button (scroll wheel).

void setButton(int button, boolean state);.
Description: sets state for given mouse button, which is persisted and affects further calls to move, scroll and click methods.

boolean getButton(int button);.
Description: returns state of mouse button.

void releaseAllButtons();.
Description: releases all mouse buttons.

void delayMouse(int duration);
Description: waits at least duration milliseconds (not guaranteed to be precise, may be a few milliseconds longer) before sending next mouse reports.

void sendMouseReport(byte buttons, byte x, byte y, byte scroll);
Description: sends custom USB mouse report containing data specified by parameters. If protocol is set to BOOT, value of scroll will be ignored. Does not change state of the object!

int getMouseProtocol();
Description: returns value of protocol set by USB host.
PROTOCOL_BOOT - for simplified boot protocol.
PROTOCOL_REPORT  - for report protocol.

 
USBConsumerControl
Input device that allows to control media playback, system volume, power state, launch applications (browser, e-mail client etc.). Keep in mind that some actions are not supported by all operating systems or results of given action may be different, depending on OS.

Public methods:

void consumerReport(int code);
Description: sends consumer control report containing specified code.
VOL_UP - increase system volume.
VOL_DOWN - decrease system volume.
VOL_MUTE - mute/unmute.
(...)

void systemReport(int code);
Description: sends system report containing specified code.
POWER_DOWN - power down system.
SLEEP - put system to stand-by.
(...)

void delayConsumer(int duration);
Description: waits at least duration milliseconds (not guaranteed to be precise, may be a few milliseconds longer) before sending next consumer control reports.
 

USBGamepad
Generic USB gamepad: 16 buttons and 4 axes (X,Y,Z,rZ).

Public methods:

void setXAxis(int value);
Description: sets value of X axis, which is persisted and affects further calls to sendGamepadReport method.

void setYAxis(int value);
Description: sets value of Y axis, which is persisted and affects further calls to sendGamepadReport method.

void setZAxis(int value);
Description: sets value of Z axis, which is persisted and affects further calls to sendGamepadReport method.

void setRZAxis(int value);
Description: sets value of rZ axis, which is persisted and affects further calls to sendGamepadReport method.

void resetAxes();.
Description: sets all axes to 0. Affects further calls to sendGamepadReport method.

void setButton(int button, boolean state);.
Description: sets state for given gamepad button (1-16), which is persisted and affects further calls to sendGamepadReport method.

boolean getButton(int button);.
Description: returns state of gamepad button (1-16).

void releaseAllButtons();.
Description: releases all gamepad buttons. Affects further calls to sendGamepadReport method.

void delayGamepad(int duration);
Description: waits at least duration milliseconds (not guaranteed to be precise, may be a few milliseconds longer) before sending next gamepad reports.

void sendGamepadReport();
Description: sends USB gamepad report, which is based on current state of the object (buttons, axes).

void sendGamepadReport(byte buttons1, byte buttons2, byte x, byte y, byte z, byte rz);
Description: sends custom USB gamepad report containing data specified by parameters. Does not change state of the object!


USBKeyobardMouse
Composite USB device composed of three interfaces: USB keyboard, USB Mouse and USB ConsumerControl.

Public methods: same as in USBKeyboard, USBMouse and USBConsumerControl.


In most cases using these classes should be easy and produce expected results. However we should not make any assumptions about USB host: hardware (PC or maybe a game console), operating system, keyboard layout and screen resolution. With USB mouse, solution is quiet simple: simple sensitivity setting. In case of USB keyboard it is more complicated, since there are dozens of keyboard layouts. I came up with an idea, to enter characters using Unicode, but unfortunately this is OS-dependent (Alt+ numeric keypad digits on Windows).

Friday 12 July 2013

Enclosure with custom logo

I know that this probably doesn't look too impressive, but for now it should do:

I'm about to order several such enclosures. Hope I will get them soon :)

Monday 8 July 2013

InputStick API

Many Android applications can benefit form using InputStick: remote controllers, password managers, barcode scanners and many more. My main goal was to design API in such a way, that using InputStick in existing applications will be fast and easy.

InputStick API is divided into two layers: API classes and Utility application consisting of  background service and user interface. This separates interface which represents USB device form the whole mechanism that uses InputStick to emulate it. InputStick API uses inter-process communication to exchange data with background service.


This allowed to achieve following goals:
  • using InputStick in Android applications is very easy.
  • user application does not need Bluetooth permissions.
  • most of InputStick-related user interactions are handled by InputStickUtility, which always provides user with the same interface.
  • maintaining compatibility of applications using older API version with possible newer firmware/protocol.
  • increased data security.
  • protecting hardware form being simultaneously accessed by more than one application.
Are there any drawbacks? Inter-process communication introduces additional latency, still it is less than a millisecond on most mid-end and high-end devices. Of course it also consumes some additional system resources, but that is a small price to pay for all the advantages.


InputStick API classes.

InputStick API is a set of Java classes that are directly used in application. API takes care of communicating with background service. In case if InputStickUtility is not installed, it will ask user to download the application form Google Play (at this moment it is not yet released). Most applications will use one of following standard device classes:
  • USB Keyboard
  • USB Mouse
  • USB Gamepad
  • USB Keyboard & USB Mouse & USB Consumer Control
where all it takes is to call methods corresponding to desired behaviour of the device (press key, move cursor, click, etc). Application should also handle callbacks generated when there is a change of connection state or when USB data is received (example: change of keyboard LEDs: NumLock, CapsLock, ScrollLock). Developer can focus on implementing additional functionality, while everything USB-related is taken care of by the API.

If you would like to emulate non-standard USB device, API provides a set of classes that allows you to use Java to create:
  • USB Descriptors (to define device capabilities)
  • USB Requests (define how to respond to specific type of USB host request)
  • Endpoint Configuration, Data Buffers Configuration etc.
This allows to emulate almost any kind of USB HID (Human Interface Device) hardware, but keep in mind that there are some limitations (more on that at the end).


InputStickUtility.

InputStickUtility is an Android application that is required to be installed on any Android device that will be used with InputStick. Utility application provides user interface that takes care of:
  • pairing with InputStick devices.
  • selecting appropriate InputStick device at a given moment.
  • displaying notifications.
  • handling connection errors.
  • performing firmware upgrade.
User benefits form the fact that all InputStick related activities are always performed in exactly the same manner, regardless of what application wants to use InputStick, while application developers do not have to include additional user interface elements. The other task of Utility application is handled by background service. It acts as a proxy between users application and InputStick hardware. This allows to protect InputStick hardware form simultaneous access form two applications and does not allow user applications to modify internal firmware. Since all traffic goes through the service, it can maintain compatibility with applications compiled using previous API versions, in case if new communication protocol is introduced in the future. Last but not least, user application is simpler since it does not have to manage Bluetooth connection and everything related to that (enabling Bluetooth radio, dealing with unexpected situation like loosing connection, etc.).


Limitations.

InputStick can be recognised by USB host as any (full speed) USB device, depending on provided USB descriptors. However that does not mean that you can actually make it work. There are three main limiting factors:

Bluetooth: InputStcik communicates with Android device using Bluetooth link. This limits maximum data throughput to 12.5 KBps, what results in approximately 10 KBps for user data, after taking into account overhead introduced by transport protocol. It also introduces several milliseconds of latency.

USB: interrupt transfer type, used in HID devices, allows to set minimal polling interval to 1 millisecond, what limits maximal number of reports per second to 1000.

API: InputStick API allows to emulate most of Human Interface Devices and many other kinds of USB devices, however it may not be possible to emulate some types of devices which express non-standard behaviour.

To sum up: InputStick should allow to emulate most of Human Interface Devices, where 10 KBps throughput is in most cases enough to provide data even for 1000 reports every second. It should be also possible to implement mass storage device, however 5 KBps transfer rate (additional overhead and latency must be taken into account) makes it rather impractical. Finally, 10 KBps is simply not enough for audio class.

 
Example.

Here is a simple example of how to use InputStick API in Android application. Application emulates USB keyboard and when user presses a button, it types "Hello world!". Let's start with a source code:


Here is what we get:

Main Activity.
 
InputStickUtility takes care of asking user to select InputStick device to use.


Just a few more seconds...

Connected!

InputStick is detected as a generic USB keyboard.


This is a result of pressing "Say Hello" button.

As you can see, it was enough to add several lines of code to allow Android application to use InputStick to emulate USB keyboard.

I hope that this more or less explains how InputStick API is designed. There is still some work to be done, but I estimate that I should be able to release it by the end of this month.

Tuesday 2 July 2013

InputStick and PlayStation 3

Just a quick post related to PlayStation 3. PS3 supports many different kinds of USB devices, but I'm mainly interested in the following: keyboard, mouse and gamepad. Unfortunately there are some limitations: you can't use keyboard or mouse to play games, also generic HID gamepad is supported only by some titles (for example: Dirt Showdown).

What I've been able to confirm is that my implementation of:
  • USB Keyboard: works
  • USB Mouse: works
  • USB Consumer Control: does not work :(
  • USB Keyboard & Mouse: works
  • USB Gamepad: works (as a generic HID gamepad, only with some games)

I guess that next step is to implement emulation of original PS3 controller. I've done a little bit of research and I think that I should be able to do this, using InputStick, although it's a bit tricky, since PS3 controller is not a typical HID device and it uses some custom protocol. For now, there are more important things that have to be done, but I will for sure come back to this subject later.
 
I'm aware of the fact that there are already apps like Blueputdroid that allow to control PS3 via Bluetooth, however your phone must be rooted, also it is not compatible with all phones. With InputStick this is not an issue anymore.