Introduction
The VictoR SDK will provide end-users with an Android Communications library that enables them to communicate with a VictoR device over various communication protocols within their Android-based applications.. One of the supported protocols of this library will be the Universal Serial Bus (USB) protocol. The following design explains how support for the USB protocol will be implemented for Android.
Requirements
Related Jira Issues
Jira Legacy | ||||||
---|---|---|---|---|---|---|
|
Constraints
Performance
Calls to a VictoR device are time intensive I/O operations. The Communications Interface should not block and force the end-user to wait for those operations to complete. It should instead return the results asynchronously through callbacks.
Operating System
This Communications Interface implementation will be provided as an Android Library written in Java and compiled into an Android Archive (AAR), enabling VictoR device application development for hardware targets running Android 10 and above.
Ease of Use
Interacting with a USB device is a complicated multi-step process for almost every interaction. The Communications Interface should abstract this process away from the end-user so that they don’t need to know all of the OS-specific implementation details for communicating with a VictoR device over USB. All they have to do is use the simple set of functions provided by the interface.
Detailed Design
Anchor | ||||
---|---|---|---|---|
|
The Android USB Communications API will be composed primarily of two classes: VictorUsbDevice and VictorUsbDeviceManager. These classes are implementations of the abstract VictorDevice and VictorDeviceManager interfaces provided by the VictoR Core library. The VictorUsbDevice class represents the connection interface to an individual VictoR device over a physical USB cable. This class handles all interactions with that device over the USB communications protocol, including connecting/disconnecting, reading/writing data, and subscribing/unsubscribing from events for that device like attribute (characteristic) changes and connection state changes. These interactions are implemented using a combination of the USB API provided by the Android SDK and the API provided by the USB Serial for Android library, as discussed below in the Dependencies section. The details of the specific function calls required are outlined below in the Implementation section. The VictorUsbDeviceManager manages all VictoR device connection interfaces through VictorUsbDevice objects that it creates, maintains, and destroys as needed. This class acts as the primary interface for end-users to discover devices and manage connections to them. In addition, the VictorUsbDeviceManager provides a wrapper around the functions that the VictorUsbDevice class offers, requiring only that the end-user provide the address for the specific device they are interested in interacting with, so that they don’t need to have any knowledge of the underlying organization of the devices within the manager. The class diagram in Figure 1 below illustrates the architecture of the Android USB Communications API.
Anchor | ||||
---|---|---|---|---|
|
The Android SDK does not provide out of the box support for communication with a serial device over USB. It only provides several generic USB device classes that can be used to build a serial device abstraction. Fortunately, the USB Serial for Android library already provides a serial device abstraction using these classes. This library will be utilized to reduce development time and interface complexity.
Anchor | ||||
---|---|---|---|---|
|
The following outline describes the function calls to the Android SDK and USB Serial for Android library that will be used, as well as a general outline of the algorithm for the function using them, for all of the functions provided by the Android USB Communications API.
VictorUsbDevice
Connect
Open a UsbDeviceConnection on the UsbSerialDriver’s UsbDevice using UsbManager.openDevice
Get the correct UsbSerialPort from the UsbSerialDriver using UsbSerialDriver.getPorts
Most devices only have one port
Preliminary prototyping has shown that the VictoR device exposes two ports
The correct port appears to be the 2nd port (port 1, not port 0)
Open the port, providing the open UsbDeviceConnection using UsbSerialPort.open
Disconnect
As with connect, get the correct UsbSerialPort from the UsbSerialDriver using UsbSerialDriver.getPorts
Close the port using UsbSerialPort.close
This also closes the open UsbDeviceConnection
Read
Send a read request using UsbSerialPort.write
Read the response using UsbSerialPort.read
Write
Send a write request using UsbSerialPort.write
Verify the write was successful by reading the response using UsbSerialPort.read
Subscribe to Connection State Changes
Add the provided user callback to the set of connection state change callbacks
When the device connects or disconnects, invoke each callback in the set with the corresponding connection state
To detect connection state changes, a thread will be needed to continuously poll the serial port status
If the device is disconnected, an attempt to reconnect should be made.
Unsubscribe from Connection State Changes
Remove the provided user callback from the set of connection state change callbacks
Subscribe to Attribute Changes
Send a subscribe request using UsbSerialPort.write
Verify the subscribe was successful by reading the response using UsbSerialPort.read
This is not possible as it appears the VictoR firmware doesn’t currently support this.
Success will instead indicate that the request was successfully communicated to the device, not necessarily that the device acknowledged it.
Unsubscribe from Attribute Changes
Send an unsubscribe request using UsbSerialPort.write
Verify the unsubscribe was successful by reading the response using UsbSerialPort.read
This is not possible as it appears the VictoR firmware doesn’t currently support this.
Success will instead indicate that the request was successfully communicated to the device, not necessarily that the device acknowledged it.
VictorUsbDeviceManager
Scan for Devices
Using the Android SDK:
Get the UsbManager from the application Context using Context.getSystemService
Using the USB Serial for Android library:
Create a ProbeTable with the Vendor ID and Product ID of the VictoR device
Create a custom UsbSerialProber using this custom ProbeTable
Use this custom UsbSerialProber to find all UsbSerialDrivers using UsbSerialProber.findAllDrivers
findAllDrivers is not a timed, asynchronous operation
UsbSerialProber has no concept of a scan time
This class will ignore the scan time field of the VictorDeviceScanParameters provided to it
API documentation for this class will make note of this fact
Track all UsbSerialDrivers discovered in a map keyed on the device name (address) using UsbDevice.getDeviceName()
Use the Android Intent system to request permission to communicate with the UsbDevice within each UsbSerialDriver as outlined here
Get all Devices
Maintain a map of all UsbSerialDrivers that have been scanned, connected, or disconnected at any point
Key the map using UsbDevice.getDeviceName()
Get Scanned Devices
Maintain a map of all UsbSerialDrivers that have been discovered during the last scan
Key the map using UsbDevice.getDeviceName()
Clear the map each time a scan is performed
Get Connected Devices
Maintain a map of all UsbSerialDrivers that are currently connected
Key the map using UsbDevice.getDeviceName()
Add devices as they are connected
Remove devices when they disconnect
Connect
Find the specified device from the map of connected devices
If it can be found, then call Device.Connect
Disconnect
Find the specified device from the map of connected devices
If the device is found, then call Device.Disconnect
Read
Find the specified device from the map of connected devices
If the device is found, then call Device.Read
Write
Find the specified device from the map of connected devices
If the device is found, then call Device.Write
Subscribe to Connection State Changes
Find the specified device from the map of connected devices
If the device is found, then call Device.SubscribeConnectionStateChange
Unsubscribe from Connection State Changes
Find the specified device from the map of connected devices
If the device is found, then call Device.UnsubscribeConnectionStateChange
Subscribe to Attribute Changes
Find the specified device from the map of connected devices
If the device is found, then call Device.SubscribeAttributeChange
Unsubscribe from Attribute Changes
Find the specified device from the map of connected devices
If the device is found, then call Device.UnsubscribeAttributeChange
Unity Project Integration
Unity natively supports integration of AAR plug-ins and JAR plug-ins.
The Android USB Communications API will be imported as an AAR plug-in and wrapped in C# scripts using the AndroidJavaObject and AndroidJavaClass classes.
The USB Serial For Android library will be imported as a JAR plug-in and referenced by the Android USB Communications AAR plug-in.
Any Java Future<T> objects will be translated to C# Task<T> objects
Any Java Callback Interfaces will be translated to C# Action<T> function calls.
Glossary
Term | Description |
---|---|
API | Application Programming Interface |
AAR | Android Archive |
End-User | A developer utilizing the VictoR SDK libraries for software application development |
I/O | Input/Output |
OS | Operating System |
SDK | Software Development Kit |
USB | Universal Serial Bus |
UUID | Universally Unique Identifier |