Android 3.1 and above devices support Usb host mode. With this feature you can connect to regular client usb devices. Some devices are automatically recognized by the OS and are simple to work with, such as: keyboard, mouse or storage devices.
Other devices require the developer to implement the specific protocol. Depending on the device and the documentation available this can be a feasible task.
This example which is based on Google's AdbTest example, connects two Android devices with a Usb cable. The host device reads the client device logs. This is done by implementing one feature of Adb debugging, similar to the Usb debugging driver.
The logs of the host device show messages from the client device:
As the Usb host features are only available starting with Android 3.1, you should configure the IDE to use android.jar level 12 or above. It can be downloaded by choosing Tools - Run AVD manager.
You should then configure the IDE paths to point to the correct android.jar:
The following error means that you are using the wrong platform level:
Now to the code...
The first step is to use UsbManager to find all the connected devices. We are going over all devices, looking for a device with an interface with class = 255 and subclass = 66.
Assuming that such a device is found we are also looking for the in / out endpoints.
The following code iterates over the connected devices (usually there will be one) looking for the requested values:
The next step is to check if we have permission to access this device and request such a permission if we don't have. The permission will only be required on the first time our application runs.
RequestPermission will show a dialog asking the user to approve the request.
If we do have permission we connect to the device:
First we connect to the device and send to OUT requests according to the ADB protocol and one IN request that will return with the result from the device.
We then call connection.StartListening to notify the listener to listen for completed requests.
Adb protocol
In order to start a connection we need to send a pair of requests. One is the "message" and the other is the "data".
These requests are sent to the OUT endpoint as we are sending data from the host to the device.
In order to get the device response we are sending another request to the IN endpoint.
Our code will continue in Sub NewData when the IN request completes.
Note that each request can be assigned a name. This is an arbitrary string that helps us identify the requests that return in NewData event. For 'out' requests the name is not really important.
Now for the NewData event handling which is a bit more complicated:
We are only interested in IN requests. The InDirection boolean parameter is useful distinguish between the requests:
UsbRequest object are "heavy" objects. We are using a simple pool of objects to avoid creating new requests every time.
So the above code returns the request to the pool and then call connection.ContinueListening. This tells the listener to continue listening for requests. Without calling it we will not get the event for the IN request that we are waiting for.
If the request is an IN request things are more interesting. We check the name of the request to know if it is a "message" request or a "data" request.
We then call DispatchMessage. This sub handles the message based on the message command.
After getting an IN request there are two possible cases. The first is that we got a message request and we need to also receive the data message. The length of the data message is retrieved from the content of the message request.
In the other case we send another IN message request waiting for the next update from the device.
Eventually we release the request and call connection.ContinueListening.
RandomAccessFile object is used in several occasions to prepare the buffers according to the protocol.
B4A-Bridge
It is not possible to cannot connect the IDE to the Usb port of the host device as it is taken by the client. B4A-Bridge should be used instead: B4A-Bridge a new way to connect to your device
The project is attached.
The library is available here: http://www.b4x.com/forum/additional-libraries-official-updates/11290-usb-host-library.html#post63118
Other devices require the developer to implement the specific protocol. Depending on the device and the documentation available this can be a feasible task.
This example which is based on Google's AdbTest example, connects two Android devices with a Usb cable. The host device reads the client device logs. This is done by implementing one feature of Adb debugging, similar to the Usb debugging driver.
The logs of the host device show messages from the client device:
As the Usb host features are only available starting with Android 3.1, you should configure the IDE to use android.jar level 12 or above. It can be downloaded by choosing Tools - Run AVD manager.
You should then configure the IDE paths to point to the correct android.jar:
The following error means that you are using the wrong platform level:
B4X:
package android.hardware.usb does not exist
Now to the code...
The first step is to use UsbManager to find all the connected devices. We are going over all devices, looking for a device with an interface with class = 255 and subclass = 66.
Assuming that such a device is found we are also looking for the in / out endpoints.
The following code iterates over the connected devices (usually there will be one) looking for the requested values:
B4X:
Sub FindAdbDevice As Boolean
Dim usbdevices() As UsbDevice
usbdevices = manager.GetDevices
'Iterate over devices and find the correct one
For i = 0 To usbdevices.Length - 1
Dim ud As UsbDevice
ud = usbdevices(i)
Log(ud)
'Iterate over interfaces
For a = 0 To ud.InterfaceCount - 1
Dim inter As UsbInterface
inter = ud.GetInterface(a)
If inter.InterfaceClass = 255 AND inter.InterfaceSubclass = 66 Then
'found our device and interface
device = ud
interface = inter
'Find correct endpoints
For b = 0 To interface.EndpointCount - 1
Dim endpoint As UsbEndpoint
endpoint = interface.GetEndpoint(b)
If endpoint.Type = manager.USB_ENDPOINT_XFER_BULK Then
If endpoint.Direction = manager.USB_DIR_IN Then
inEndpoint = endpoint
Else If endpoint.Direction = manager.USB_DIR_OUT Then
outEndpoint = endpoint
End If
End If
Next
End If
Next
Next
If device.IsInitialized = False Then Log("ADB device not found.")
End Sub
The next step is to check if we have permission to access this device and request such a permission if we don't have. The permission will only be required on the first time our application runs.
B4X:
If manager.HasPermission(device) = False Then
manager.RequestPermission(device)
...
If we do have permission we connect to the device:
B4X:
connection = manager.OpenDevice(device, interface, True)
Log("Starting connection")
Dim data(), msg() As Byte
data = ConvertStringToBytesWith0("host::" & Chr(0))
msg = CreateMessage(A_CNXN, 0x01000000, 4096, data)
SendOutRequest("Msg", msg, 24)
SendOutRequest("Data", data, Data.Length)
SendInRequest(MSG_READ, 24)
connection.StartListening("connection")
We then call connection.StartListening to notify the listener to listen for completed requests.
Adb protocol
In order to start a connection we need to send a pair of requests. One is the "message" and the other is the "data".
These requests are sent to the OUT endpoint as we are sending data from the host to the device.
In order to get the device response we are sending another request to the IN endpoint.
Our code will continue in Sub NewData when the IN request completes.
Note that each request can be assigned a name. This is an arbitrary string that helps us identify the requests that return in NewData event. For 'out' requests the name is not really important.
Now for the NewData event handling which is a bit more complicated:
B4X:
Sub Connection_NewData (Request As UsbRequest, InDirection As Boolean)
If Connection.IsInitialized = False Then Return 'Might happen after we close the connection
If InDirection = False Then
ReleaseRequest(Request, OutRequests)
connection.ContinueListening
Return 'don't handle OUT requests
End If
Dim sendData As Boolean
If Request.Name = MSG_READ Then
Dim raf As RandomAccessFile
raf.Initialize3(Request.Buffer, True)
Dim command As Int
command = raf.ReadInt(0)
If command = A_CNXN OR command = A_WRTE Then
lastCommand = command
SendInRequest(DATA_READ, raf.ReadInt(12)) 'read the data request
sendData = True
Else
DispatchMessage(command, raf.ReadInt(4), "")
End If
Else If Request.Name = DATA_READ Then
Dim s As String
s = BytesToString(Request.Buffer, 0, Request.Buffer.Length, "UTF8")
DispatchMessage(lastCommand,0, s)
End If
If sendData = False AND connection.IsInitialized Then
SendInRequest(MSG_READ, 24)
End If
ReleaseRequest(Request, InRequests)
connection.ContinueListening
End Sub
B4X:
If InDirection = False Then
ReleaseRequest(Request, OutRequests)
connection.ContinueListening
Return 'don't handle OUT requests
End If
So the above code returns the request to the pool and then call connection.ContinueListening. This tells the listener to continue listening for requests. Without calling it we will not get the event for the IN request that we are waiting for.
If the request is an IN request things are more interesting. We check the name of the request to know if it is a "message" request or a "data" request.
We then call DispatchMessage. This sub handles the message based on the message command.
After getting an IN request there are two possible cases. The first is that we got a message request and we need to also receive the data message. The length of the data message is retrieved from the content of the message request.
In the other case we send another IN message request waiting for the next update from the device.
Eventually we release the request and call connection.ContinueListening.
RandomAccessFile object is used in several occasions to prepare the buffers according to the protocol.
B4A-Bridge
It is not possible to cannot connect the IDE to the Usb port of the host device as it is taken by the client. B4A-Bridge should be used instead: B4A-Bridge a new way to connect to your device
The project is attached.
The library is available here: http://www.b4x.com/forum/additional-libraries-official-updates/11290-usb-host-library.html#post63118