This is my first experience working with USB communication and an android app.
I'm using https://github.com/felHR85/UsbSerial to create a application that will allow tablets/phones to use USB OTG to act as a host and communicate with an accessory. I have gotten to the point where I'm using the SerialInputStreams and SerialOutputStreams to send and receive with the device.
This is about the maximum packet size a USB can send being 64 bytes with the cable I'm using. On my application, the accessory is sending data that is larger than 64 bytes. If the accessory does not have code that sends the data over in 64 byte packages, but instead all of it at once. Will any data that comes after 64 bytes be lost?
I'm receiving the first 64 bytes of the message from the accessory to the host and then host times out as it doesn't receive the full message and resends to the accessory. The first 64 bytes of the message are always what show up, that way I know the other parts of the message aren't waiting to be polled.
EDIT
The device I'm connecting to is a datalogger that is taken as a CDC device. I know that the connection I'm using has a maximum packet size of 64.
The USBConnectActivity happens whenever a usb device is attached and passes the filter that I have set up, and the interface and endpoints are correct.
public class USBConnectActivity extends Activity
{
public UsbDevice device = null;
public UsbManager manager = null;
public UsbDeviceConnection usbDeviceConnection = null;
public UsbSerialDevice serialPort = null;
public String deviceID = "";
public boolean isUSBConnected = false;
private PendingIntent mPermissionIntent;
private final String ACTION_USB_PERMISSION =
"com.android.example.USB_PERMISSION";
private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
stopUsbConnection();
unregisterReceiver(usbReceiver);
}
if(ACTION_USB_PERMISSION.equals(action))
{
setupCom();
}
}
};
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
manager = (UsbManager) getSystemService(Context.USB_SERVICE);
USBConnection.getInstance().setManager(manager);
mPermissionIntent = PendingIntent.getBroadcast(
this,0,new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter mfilter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(usbReceiver,mfilter);
IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(usbReceiver, filter);
findDevice(mPermissionIntent);
finish();
}
private void findDevice(PendingIntent i)
{
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
boolean found = false;
UsbDevice xDevice = null;
while (deviceIterator.hasNext()) {
UsbDevice tDevice = deviceIterator.next();
// Loop through the interfaces of the attached USB device
for (int count = 0; count < tDevice.getInterfaceCount(); count++) {
if (found) break;
// Use temp variables to check and then match with the private variables
UsbInterface inter = tDevice.getInterface(count);
UsbEndpoint tOut = null;
UsbEndpoint tIn = null;
if (inter.getEndpointCount() >= 2) {
for (int end_count = 0; end_count < inter.getEndpointCount(); end_count++) {
UsbEndpoint end = inter.getEndpoint(end_count);
if (end.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (end.getDirection() == UsbConstants.USB_DIR_OUT) tOut = end;
else if (end.getDirection() == UsbConstants.USB_DIR_IN) tIn = end;
}
}
}
if (tOut != null && tIn != null) {
device = tDevice; manager.requestPermission(device, i); found = true;
isUSBConnected = true;
USBConnection.getInstance().setDevice(device);
USBConnection.getInstance().attach();
}
}
}
if(usbDeviceConnection == null) setupCom();
}
#Override
protected void onStop()
{
super.onStop();
unregisterReceiver(usbReceiver);
}
private void setupCom()
{
deviceID = device.getDeviceName();
if(usbDeviceConnection == null) usbDeviceConnection = manager.openDevice(device);
if(serialPort == null)
{
serialPort = UsbSerialDevice.createUsbSerialDevice(device, usbDeviceConnection);
if(serialPort != null && serialPort.open())
{
serialPort.setBaudRate(115200);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
USBConnection.getInstance().setSerialPort(serialPort);
USBConnection.getInstance().setUsbDeviceConnection(usbDeviceConnection);
}
}
}
private void stopUsbConnection(){
manager = null;
device = null;
isUSBConnected = false;
USBConnection.getInstance().detach();
deviceID = "";
try
{
if(serialPort != null)
serialPort.close();
if(usbDeviceConnection != null)
usbDeviceConnection.close();
}
finally
{
serialPort = null;
usbDeviceConnection = null;
}
}
}
This class holds all the USB info
public class USBConnection
{
// USB information
public boolean isConnected;
public UsbDevice device;
public UsbManager manager;
public UsbSerialDevice serialPort;
public UsbDeviceConnection usbDeviceConnection;
public String deviceName;
public boolean waitForReading;
private static USBConnection instance;
public static USBConnection getInstance()
{
if(instance == null)
instance = new USBConnection();
return instance;
}
public void setDevice(UsbDevice device_)
{
device = device_;
deviceName = device.getDeviceName();
}
public void setManager(UsbManager manager_)
{
manager = manager_;
}
public void attach()
{
isConnected = true;
}
public void detach()
{
isConnected = false;
}
public void setSerialPort(UsbSerialDevice serialPort_)
{
serialPort = serialPort_;
}
public void setUsbDeviceConnection(UsbDeviceConnection usbDeviceConnection_)
{
usbDeviceConnection = usbDeviceConnection_;
}
public void writing() {
waitForReading = true;
}
public void reading(){
waitForReading = false;
}
public boolean waitingForRead()
{
return waitForReading;
}
}
This is the code I use to set up the input and output streams
else if(USBConnection.getInstance().isConnected) // check if usb is connected
{
manager = USBConnection.getInstance().manager;
device = USBConnection.getInstance().device;
// Attempt at setting up a USB input and output stream
if (manager != null) {
if(usbDeviceConnection == null) usbDeviceConnection = manager.openDevice(device);
if(serialPort == null)
{
serialPort = UsbSerialDevice.createUsbSerialDevice(device, usbDeviceConnection);
if(serialPort != null && serialPort.open())
{
serialPort.setBaudRate(115200);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
input = new SerialInputStream(serialPort);
output = new SerialOutputStream(serialPort);
Log.d("Direct", "Connected to the USB socket");
}
}
}
} // else there is no usb connected
This is in felHR85 UsbSerialDevice, in his ReadThread, and what is commented out is what I included thinking it would grab the data if it was larger than 64 bytes
int numberBytes, bytes;
if(inEndpoint != null) {
bytes = numberBytes = connection.bulkTransfer(inEndpoint, serialBuffer.getBufferCompatible(),
SerialBuffer.DEFAULT_READ_BUFFER_SIZE, 100);
}/*while(numberBytes >= 64) {
numberBytes = connection.bulkTransfer(inEndpoint, serialBuffer.getBufferCompatible(), bytes,
124, 100);
bytes += numberBytes;
Log.i("Bytes", " : " + bytes);
}*/
else
bytes = numberBytes = 0;
This is in his WriteThread
while(working.get())
{
byte[] data = serialBuffer.getWriteBuffer();
if(data.length > 0)
connection.bulkTransfer(outEndpoint, data, data.length, USB_TIMEOUT);
}
EDIT
This solved my problem but I'm still not sure what the answer is to my original question
if(serialPort == null)
{
usbDeviceConnection.claimInterface(USBConnection.getInstance().usbInterface, true);
usbDeviceConnection.controlTransfer(64,0,1,0,null,0,0); // clear tx
usbDeviceConnection.controlTransfer(64,0,2,0,null,0,0); // clear rx
serialPort = UsbSerialDevice.createUsbSerialDevice(device, usbDeviceConnection);
Please put up your code. Please specify any device that you are using as accessory(Arduino, FPGA, etc) so that finding solution becomes easier. It is difficult to tell what is going wrong. I suggest you to do the following -
1)Check the device descriptor of the accessory where it is clearly mentioned the maximum bytes the USB endpoint can transfer at a time. Here I have it for my Arduino Uno
2)I request you to go through this instead of using a library.
3)There is a DTR signal which must be sent form host to accessory to indicate that data transfer is complete; so that the next data can be sent.Check this
4)You should be using a ring buffer for the receiving stream so that the data is not lost.
Related
I have a button in MainActivity which is used to write a byte[] to BLE device:
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Write Char"
android:id="#+id/button2"
android:onClick="onClickWrite" />
And the function onClickWrite is
public void onClickWrite(View v){
if(mBluetoothLeService != null) {
byte [] data= new byte[3];
data[0] = (byte)(0 & 0xFF);
data[1] = (byte)(255 & 0xFF);
data[2] = (byte)(0 & 0xFF);
mBluetoothLeService.sendData(data);
}
}
where sendData is a modified function in class [BluetoothLeService][1]. It worked well when I press the button. However, Let is careful to look at the sendData function. It searches service and Characteristic again when I press the button. Is it correct procedure for write a Characteristic in BLE?
public void sendData(byte[] data){
String lService = "00001c00-d102-11e1-9b23-00025b00a5A5";
String lCharacteristic = "00001c03-d102-11e1-9b23-00025b00a5a5";
BluetoothGattService mBluetoothLeService = null;
BluetoothGattCharacteristic mBluetoothGattCharacteristic = null;
for (BluetoothGattService service : mBluetoothGatt.getServices()) {
if ((service == null) || (service.getUuid() == null)) {
Log.d("TAG","Something is null");
continue;
}
if (lService.equalsIgnoreCase(service.getUuid().toString())) {
Log.d("TAG","service.getUuid().toString()="+service.getUuid().toString());
mBluetoothLeService = service;
}
}
if(mBluetoothLeService!=null) {
mBluetoothGattCharacteristic =
mBluetoothLeService.getCharacteristic(UUID.fromString(lRgbCharacteristic));
}
else{
Log.d("TAG","mBluetoothLeService is null");
}
if(mBluetoothGattCharacteristic!=null) {
mBluetoothGattCharacteristic.setValue(data);
boolean write = mBluetoothGatt.writeCharacteristic(mBluetoothGattCharacteristic);
Log.d("TAG","writeCharacteristic:"+write);
}
else{
Log.d("TAG", "mBluetoothGattCharacteristic is null");
}
}
Yes.
(filling unnecessarily required length)
public boolean OpenDevice() {
_usbManager = (UsbManager) _context.getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = _usbManager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
_usbDevice = null;
// Iterate all the available devices and find ours.
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next();
if (device.getProductId() == _productId && device.getVendorId() == _vendorId) {
_usbDevice = device;
_deviceName = _usbDevice.getDeviceName();
}
}
if (_usbDevice == null) {
Toast.makeText(_context,"Cannot find the device. Did you forgot to plug it?",Toast.LENGTH_SHORT).show();
return false;
}
// Create and intent and request a permission.
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(_context, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
_context.registerReceiver(mUsbReceiver, filter);
_usbManager.requestPermission(_usbDevice, mPermissionIntent);
UsbInterface writeIntf = _usbDevice.getInterface(0);
epOUT=writeIntf.getEndpoint(1);
epIN=writeIntf.getEndpoint(0);
mUsbDeviceConnection=_usbManager.openDevice(_usbDevice);
mUsbDeviceConnection.claimInterface(writeIntf, true);
Toast.makeText(_context,"Found the device",Toast.LENGTH_SHORT).show();
return true;
}
public byte[] read(UsbRequest outRequest) throws UsbException {
if (mUsbDeviceConnection == null) {
throw new UsbException("no connection available");
}
ByteBuffer buffer = ByteBuffer.allocate(MAX_PACKAGE_SIZE);
if (outRequest.equals(mUsbDeviceConnection.requestWait())) {
UsbRequest inRequest = new UsbRequest();
inRequest.initialize(mUsbDeviceConnection, epIN);
if (inRequest.queue(buffer, MAX_PACKAGE_SIZE)) {
mUsbDeviceConnection.requestWait();
return buffer.array();
}
}
return null;
}
public UsbRequest write(byte[] command) throws UsbException {
if (mUsbDeviceConnection == null) {
throw new UsbException("no connection available");
}
ByteBuffer buffer = ByteBuffer.allocate(1);
UsbRequest outRequest = new UsbRequest();
outRequest.initialize(mUsbDeviceConnection, epOUT);
buffer.put(command);
outRequest.queue(buffer, 1);
return outRequest;
}
public byte[] sendCommand(byte[] command) throws UsbException {
UsbRequest request = write(command);
_textInfo.setText(_textInfo.getText()+"\n" +request );
return read(request);
}
I am trying to push some command at endPointOut and trying to receive data from endPointIN but when i am trying to read using mUsbDeviceConnection.requestWait() application is not responding
following code that how i am trying to call these function
byte b=(byte)'x';
byte command[] = {b};
byte[] result= hidBr.sendCommand(command);
I am getting a blank array
I'am able to connect to device and ask device specifications:
specs:
Model: /dev/bus/usb/001/002
ID: 1002
Class: 0
Protocol: 0
Vendor ID 1155
Product ID: 22352
Interface count: 1
---------------------------------------
***** *****
Interface index: 0
Interface ID: 0
Inteface class: 3 USB_CLASS_HID
Interface protocol: 0
Endpoint count: 2
++++ ++++ ++++
Endpoint index: 0
Attributes: 3
Direction: 128 (device to host)
Number: 1
Interval: 1
Packet size: 64
Type: 3 USB_ENDPOINT_XFER_INT (interrupt endpoint)
++++ ++++ ++++
Endpoint index: 1
Attributes: 3
Direction: 0 (host to device)
Number: 1
Interval: 1
Packet size: 64
Type: 3 USB_ENDPOINT_XFER_INT (interrupt endpoint)
No more devices connected.
I'am also able to send data from host to device, using this method:
int bufferDataLength = mEndpointOut.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1);
UsbRequest request = new UsbRequest();
buffer.put(DataToSend);
request.initialize(mDeviceConnection, mEndpointOut);
request.queue(buffer, bufferDataLength);
try
{
if (request.equals(mDeviceConnection.requestWait()))
{
// Read an analyze the incoming data here
byte[] byteBuffer = new byte[buffer.remaining()];
buffer.get(byteBuffer, 0, buffer.remaining());
return true;
}
}
catch (Exception ex)
{
Log.e(TAG, "Error sending data: " + ex.toString());
}
return false;
But i'am not able to read from device, i've tested several methods without success..
for example this doesn't work:
int bufferDataLength = mEndpointIn.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1);
//Make a request
UsbRequest request = new UsbRequest();
request.initialize(mDeviceConnection, mEndpointIn);
ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength);
//For IN endpoints, data is read into the buffer
request.queue(buffer, bufferDataLength);
//This blocks until the request is successful
//Make sure the request that finished is the one you need
if (mDeviceConnection.requestWait() == request) {
// Read an analyze the incoming data here
byte[] byteBuffer = new byte[buffer.remaining()];
buffer.get(byteBuffer, 0, buffer.remaining());
}
Suggestions?
I resolved my problems using this class, i'm answering to my my question hoping it can help someone else:
/**
* This class is used for talking to hid of the dongle, connecting, disconnencting and enumerating the devices.
* #author gai
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
public class HidBridge {
private Context _context;
private int _productId;
private int _vendorId;
//private HidBridgeLogSupporter _logSupporter = new HidBridgeLogSupporter();
private static final String ACTION_USB_PERMISSION =
"com.example.company.app.testhid.USB_PERMISSION";
// Locker object that is responsible for locking read/write thread.
private final Object _locker = new Object();
private Thread _readingThread = null;
private boolean _runReadingThread = false;
private String _deviceName;
private UsbManager _usbManager;
private UsbDevice _usbDevice;
// The queue that contains the read data.
private Queue<byte[]> _receivedQueue;
/**
* Creates a hid bridge to the dongle. Should be created once.
* #param context is the UI context of Android.
* #param productId of the device.
* #param vendorId of the device.
*/
public HidBridge(Context context, int productId, int vendorId) {
_context = context;
_productId = productId;
_vendorId = vendorId;
_receivedQueue = new LinkedList<byte[]>();
}
/**
* Searches for the device and opens it if successful
* #return true, if connection was successful
*/
public boolean OpenDevice() {
_usbManager = (UsbManager) _context.getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = _usbManager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
_usbDevice = null;
// Iterate all the available devices and find ours.
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next();
if (device.getProductId() == _productId && device.getVendorId() == _vendorId) {
_usbDevice = device;
_deviceName = _usbDevice.getDeviceName();
}
}
if (_usbDevice == null) {
Log("Cannot find the device. Did you forgot to plug it?");
Log(String.format("\t I search for VendorId: %s and ProductId: %s", _vendorId, _productId));
return false;
}
// Create and intent and request a permission.
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(_context, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
_context.registerReceiver(mUsbReceiver, filter);
_usbManager.requestPermission(_usbDevice, mPermissionIntent);
Log("Found the device");
return true;
}
/**
* Closes the reading thread of the device.
*/
public void CloseTheDevice() {
try
{
StopReadingThread();
_context.unregisterReceiver(mUsbReceiver);
}
catch(RuntimeException e)
{
Log("Error happend while closing device. Usb reciver not connected.");
}
}
/**
* Starts the thread that continuously reads the data from the device.
* Should be called in order to be able to talk with the device.
*/
public void StartReadingThread() {
if (_readingThread == null) {
_runReadingThread = true;
_readingThread = new Thread(readerReceiver);
_readingThread.start();
} else {
Log("Reading thread already started");
}
}
/**
* Stops the thread that continuously reads the data from the device.
* If it is stopped - talking to the device would be impossible.
*/
public void StopReadingThread() {
if (_readingThread != null) {
// Just kill the thread. It is better to do that fast if we need that asap.
_runReadingThread = false;
_readingThread = null;
} else {
Log("No reading thread to stop");
}
}
/**
* Write data to the usb hid. Data is written as-is, so calling method is responsible for adding header data.
* #param bytes is the data to be written.
* #return true if succeed.
*/
public boolean WriteData(byte[] bytes) {
try
{
// Lock that is common for read/write methods.
synchronized (_locker) {
UsbInterface writeIntf = _usbDevice.getInterface(0);
UsbEndpoint writeEp = writeIntf.getEndpoint(1);
UsbDeviceConnection writeConnection = _usbManager.openDevice(_usbDevice);
// Lock the usb interface.
writeConnection.claimInterface(writeIntf, true);
// Write the data as a bulk transfer with defined data length.
int r = writeConnection.bulkTransfer(writeEp, bytes, bytes.length, 0);
if (r != -1) {
Log(String.format("Written %s bytes to the dongle. Data written: %s", r, composeString(bytes)));
} else {
Log("Error happened while writing data. No ACK");
}
// Release the usb interface.
writeConnection.releaseInterface(writeIntf);
writeConnection.close();
}
} catch(NullPointerException e)
{
Log("Error happend while writing. Could not connect to the device or interface is busy?");
Log.e("HidBridge", Log.getStackTraceString(e));
return false;
}
return true;
}
/**
* #return true if there are any data in the queue to be read.
*/
public boolean IsThereAnyReceivedData() {
synchronized(_locker) {
return !_receivedQueue.isEmpty();
}
}
/**
* Queue the data from the read queue.
* #return queued data.
*/
public byte[] GetReceivedDataFromQueue() {
synchronized(_locker) {
return _receivedQueue.poll();
}
}
// The thread that continuously receives data from the dongle and put it to the queue.
private Runnable readerReceiver = new Runnable() {
public void run() {
if (_usbDevice == null) {
Log("No device to read from");
return;
}
UsbEndpoint readEp;
UsbDeviceConnection readConnection = null;
UsbInterface readIntf = null;
boolean readerStartedMsgWasShown = false;
// We will continuously ask for the data from the device and store it in the queue.
while (_runReadingThread) {
// Lock that is common for read/write methods.
synchronized (_locker) {
try
{
if (_usbDevice == null) {
OpenDevice();
Log("No device. Recheking in 10 sec...");
Sleep(10000);
continue;
}
readIntf = _usbDevice.getInterface(0);
readEp = readIntf.getEndpoint(0);
if (!_usbManager.getDeviceList().containsKey(_deviceName)) {
Log("Failed to connect to the device. Retrying to acquire it.");
OpenDevice();
if (!_usbManager.getDeviceList().containsKey(_deviceName)) {
Log("No device. Recheking in 10 sec...");
Sleep(10000);
continue;
}
}
try
{
readConnection = _usbManager.openDevice(_usbDevice);
if (readConnection == null) {
Log("Cannot start reader because the user didn't gave me permissions or the device is not present. Retrying in 2 sec...");
Sleep(2000);
continue;
}
// Claim and lock the interface in the android system.
readConnection.claimInterface(readIntf, true);
}
catch (SecurityException e) {
Log("Cannot start reader because the user didn't gave me permissions. Retrying in 2 sec...");
Sleep(2000);
continue;
}
// Show the reader started message once.
if (!readerStartedMsgWasShown) {
Log("!!! Reader was started !!!");
readerStartedMsgWasShown = true;
}
// Read the data as a bulk transfer with the size = MaxPacketSize
int packetSize = readEp.getMaxPacketSize();
byte[] bytes = new byte[packetSize];
int r = readConnection.bulkTransfer(readEp, bytes, packetSize, 50);
if (r >= 0) {
byte[] trancatedBytes = new byte[r - 1]; // Truncate bytes in the honor of r
int i=0;
for (byte b : bytes) {
if (i > 0)
trancatedBytes[i - 1] = b;
i++;
}
_receivedQueue.add(trancatedBytes); // Store received data
Log(String.format("Message received of lengths %s and content: %s", r, composeString(bytes)));
}
// Release the interface lock.
readConnection.releaseInterface(readIntf);
readConnection.close();
}
catch (NullPointerException e) {
Log("Error happened while reading. No device or the connection is busy");
Log.e("HidBridge", Log.getStackTraceString(e));
}
catch (ThreadDeath e) {
if (readConnection != null) {
readConnection.releaseInterface(readIntf);
readConnection.close();
}
throw e;
}
}
// Sleep for 10 ms to pause, so other thread can write data or anything.
// As both read and write data methods lock each other - they cannot be run in parallel.
// Looks like Android is not so smart in planning the threads, so we need to give it a small time
// to switch the thread context.
Sleep(10);
}
}
};
private void Sleep(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if(device != null){
//call method to set up device communication
}
}
else {
Log.d("TAG", "permission denied for the device " + device);
}
}
}
}
};
/**
* Logs the message from HidBridge.
* #param message to log.
*/
private void Log(String message) {
//LogHandler logHandler = LogHandler.getInstance();
//logHandler.WriteMessage("HidBridge: " + message, LogHandler.GetNormalColor());
Log.i("HidBridge: ", message);
}
/**
* Composes a string from byte array.
*/
private String composeString(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b: bytes) {
builder.append(b);
builder.append(" ");
}
return builder.toString();
}
}
As I'm currently working on a little bluetooth library for Android, I'm trying to get all the service uuids of the devices I discovered in my surrounding.
When my broadcast receiver gets the BluetoothDevice.ACTION_FOUND intent, I'm extracting the device and call:
device.fetchUuidsWithSdp();
This will result BluetoothDevice.ACTION_UUID intents for each device found and I'm handling them with the same receiver:
BluetoothDevice d = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Parcelable[] uuidExtra = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
if(uuidExtra == null) {
Log.e(TAG, "UUID = null");
}
if(d != null && uuidExtra != null)
Log.d(TAG, d.getName() + ": " + uuidExtra.toString());
The thing is, that uuidExtra is always null.
How can i get all the UUIDs of the surrounding devices?
EDIT:
Im working on a Nexus 7. I tried code i found on the internet and this also gives me a NullPointerException: http://digitalhacksblog.blogspot.de/2012/05/android-example-bluetooth-discover-and.html
Thank you.
The documentation on this states...
Always contains the extra field BluetoothDevice.EXTRA_UUID
However, just like you, I have found this not to be true.
If you call fetchUuidsWithSdp() while device discovery is still taking place BluetoothDevice.EXTRA_UUID can be null.
You should wait until you receive BluetoothAdapter.ACTION_DISCOVERY_FINISHED before you make any calls to fetchUuidsWithSdp().
NOTE: This solution applies to CLASSIC bluetooth and not BLE. For BLE check how to send
manufacturer specific Data in advertiser on the peripheral side
The problem with fetching Uuids is that you have only one bluetooth adapter, and we cannot have parallel api calls which uses adapter for its purpose.
As Eddie pointed out, wait for BluetoothAdapter.ACTION_DISCOVERY_FINISHED and then call fetchUuidsWithSdp().
Still this cannot guarantee uuids to be fetched for all devices. In addition to this one must wait for each subsequent call to fetchuuidsWithSdp() to complete, and then give a call to this method for another device.
See the code below --
ArrayList<BluetoothDevice> mDeviceList = new ArrayList<BluetoothDevice>();
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = (BluetoothDevice) intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
mDeviceList.add(device);
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
// discovery has finished, give a call to fetchUuidsWithSdp on first device in list.
if (!mDeviceList.isEmpty()) {
BluetoothDevice device = mDeviceList.remove(0);
boolean result = device.fetchUuidsWithSdp();
}
} else if (BluetoothDevice.ACTION_UUID.equals(action)) {
// This is when we can be assured that fetchUuidsWithSdp has completed.
// So get the uuids and call fetchUuidsWithSdp on another device in list
BluetoothDevice deviceExtra = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Parcelable[] uuidExtra = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
System.out.println("DeviceExtra address - " + deviceExtra.getAddress());
if (uuidExtra != null) {
for (Parcelable p : uuidExtra) {
System.out.println("uuidExtra - " + p);
}
} else {
System.out.println("uuidExtra is still null");
}
if (!mDeviceList.isEmpty()) {
BluetoothDevice device = mDeviceList.remove(0);
boolean result = device.fetchUuidsWithSdp();
}
}
}
}
UPDATE: Latest android versions (mm & above) would result in triggering a pairing process with each device
Here is a good example of how to get UUIDs of service characteristics from a service that I did for getting heart rate devices:
private class HeartRateBluetoothGattCallback extends BluetoothGattCallback {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
logMessage("CONNECTED TO " + gatt.getDevice().getName(), false, false);
gatt.discoverServices();
} else if(newState == BluetoothProfile.STATE_DISCONNECTED) {
logMessage("DISCONNECTED FROM " + gatt.getDevice().getName(), false, false);
if(mIsTrackingHeartRate)
handleHeartRateDeviceDisconnection(gatt);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
logMessage("DISCOVERING SERVICES FOR " + gatt.getDevice().getName(), false, false);
if(mDesiredHeartRateDevice != null &&
gatt.getDevice().getAddress().equals(mDesiredHeartRateDevice.getBLEDeviceAddress())) {
if(subscribeToHeartRateGattServices(gatt)) {
mIsTrackingHeartRate = true;
setDeviceScanned(getDiscoveredBLEDevice(gatt.getDevice().getAddress()), DiscoveredBLEDevice.CONNECTED);
broadcastHeartRateDeviceConnected(gatt.getDevice());
} else
broadcastHeartRateDeviceFailedConnection(gatt.getDevice());
} else {
parseGattServices(gatt);
disconnectGatt(getDiscoveredBLEDevice(gatt.getDevice().getAddress()));
}
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if(characteristic.getUuid().equals(UUID.fromString(HEART_RATE_VALUE_CHAR_READ_ID))) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0)
format = BluetoothGattCharacteristic.FORMAT_UINT16;
else
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Integer heartRateValue = characteristic.getIntValue(format, 1);
if(heartRateValue != null)
broadcastHeartRateValue(heartRateValue);
else
Log.w(SERVICE_NAME, "UNABLE TO FORMAT HEART RATE DATA");
}
};
};
private void parseGattServices(BluetoothGatt gatt) {
boolean isHeartRate = false;
for(BluetoothGattService blueToothGattService : gatt.getServices()) {
logMessage("GATT SERVICE: " + blueToothGattService.getUuid().toString(), false, false);
if(blueToothGattService.getUuid().toString().contains(HEART_RATE_DEVICE_SERVICE_CHARACTERISTIC_PREFIX))
isHeartRate = true;
}
if(isHeartRate) {
setDeviceScanned(getDiscoveredBLEDevice(gatt.getDevice().getAddress()), DiscoveredBLEDevice.IS_HEART_RATE);
broadcastHeartRateDeviceFound(getDiscoveredBLEDevice(gatt.getDevice().getAddress()));
} else
setDeviceScanned(getDiscoveredBLEDevice(gatt.getDevice().getAddress()), DiscoveredBLEDevice.NOT_HEART_RATE);
}
private void handleHeartRateDeviceDisconnection(BluetoothGatt gatt) {
broadcastHeartRateDeviceDisconnected(gatt.getDevice());
gatt.close();
clearoutHeartRateData();
scanForHeartRateDevices();
}
private void disconnectGatt(DiscoveredBLEDevice device) {
logMessage("CLOSING GATT FOR " + device.getBLEDeviceName(), false, false);
device.getBlueToothGatt().close();
device.setBlueToothGatt(null);
mInDiscoveryMode = false;
}
private boolean subscribeToHeartRateGattServices(BluetoothGatt gatt) {
for(BluetoothGattService blueToothGattService : gatt.getServices()) {
if(blueToothGattService.getUuid().toString().contains(HEART_RATE_DEVICE_SERVICE_CHARACTERISTIC_PREFIX)) {
mHeartRateGattService = blueToothGattService;
for(BluetoothGattCharacteristic characteristic : mHeartRateGattService.getCharacteristics()) {
logMessage("CHARACTERISTIC UUID = " + characteristic.getUuid().toString(), false, false);
for(BluetoothGattDescriptor descriptor :characteristic.getDescriptors()) {
logMessage("DESCRIPTOR UUID = " + descriptor.getUuid().toString(), false, false);
}
if(characteristic.getUuid().equals(UUID.fromString(HEART_RATE_VALUE_CHAR_READ_ID))) {
gatt.setCharacteristicNotification(characteristic, true);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(HEART_RATE_VALUE_CHAR_DESC_ID));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
return gatt.writeDescriptor(descriptor);
}
}
break; //break out of master for-loop
}
}
return false;
}
I suppose you need to be paired with the device in order to receive the uuids.
At least, this is what happened to me.
device.getUuids() use this to get all the uuid of that paired device in the form of ParcelUuid; Example code below:-
private void get_uuid_from_paired_devices(){
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice device: pairedDevices){
for (ParcelUuid uuid: device.getUuids()){
String uuid_string = uuid.toString();
Log.d(TAG, "uuid : "+uuid_string);
}
}
}
Below worked for me to fetch the records from the remote device
-0-
registerReceiver(..,
new IntentFilter(BluetoothDevice.ACTION_UUID));
-1-
device.fetchUuidsWithSdp();
-2-from within the broadcase receiver
if (BluetoothDevice.ACTION_UUID.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Parcelable[] uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
for (Parcelable ep : uuids) {
Utilities.print("UUID records : "+ ep.toString());
}
}
You can also fetch the offline cached UUID records with
BluetoothDevice.getUuids();
I am new in SIP call using RTP, now I am trying to send and receive
voice streams using RTP for sip call. I am done with connecting
two emulators and able to send INVITE and INVITE-ACK using jain sip.
After I got an Ack I want to start RTP for media streaming, I use the RtpPacket
function to send and receive
I use RtpFunction to send media with all RTP header like this:
byte Version;
boolean Padding;
boolean Extension;
byte CC;
boolean Marker;
byte PayloadType;
short SequenceNumber;
int TimeStamp;
Please give some ideas and actual links where I can find an answer.
This can be achieved in a simpler manner
AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audio.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioGroup = new AudioGroup();
audioGroup.setMode(AudioGroup.MODE_ECHO_SUPPRESSION);
audioStream = new AudioStream(InetAddress.getByAddress(getLocalIPAddress()));
audioStream.setCodec(AudioCodec.PCMU);
audioStream.setMode(RtpStream.MODE_NORMAL);
audioStream.associate(InetAddress.getByName(SipStackAndroid.getRemoteIp()), REMOTE_PORT);
audioStream.join(audioGroup);
We send and receive RTP data using RTPpacket.
import javax.media.rtp.*;
import javax.media.rtp.rtcp.*;
import javax.media.rtp.event.*;
import javax.media.*;
import javax.media.protocol.*;
import java.net.InetAddress;
import javax.media.format.AudioFormat;
import com.sun.media.ui.*;
import java.util.Vector;
public class RTPSourceStream < RTPPlayerWindow > implements ReceiveStreamListener,
ControllerListener {
#SuppressWarnings("rawtypes")
Vector playerlist = new Vector();
#SuppressWarnings("deprecation")
SessionManager mgr = null;
boolean terminatedbyClose = false;
#SuppressWarnings("deprecation")
public SessionManager createManager(String address,
String sport,
String sttl,
boolean listener,
boolean sendlistener) {
return createManager(address,
new Integer(sport).intValue(),
new Integer(sttl).intValue(),
listener,
sendlistener);
}
#SuppressWarnings("deprecation")
public SessionManager createManager(String address,
int port,
int ttl,
boolean listener,
boolean sendlistener) {
mgr = (SessionManager) new com.sun.media.rtp.RTPSessionMgr();
if (mgr == null) return null;
mgr.addFormat(new AudioFormat(AudioFormat.DVI_RTP, 44100, 4, 1), 18);
if (listener) mgr.addReceiveStreamListener(this);
// if (sendlistener) new RTPSendStreamWindow(mgr);
// ask RTPSM to generate the local participants CNAME
String cname = mgr.generateCNAME();
String username = null;
try {
username = System.getProperty("user.name");
} catch (SecurityException e) {
username = "jmf-user";
}
// create our local Session Address
SessionAddress localaddr = new SessionAddress();
try {
InetAddress destaddr = InetAddress.getByName(address);
SessionAddress sessaddr = new SessionAddress(destaddr,
port,
destaddr,
port + 1);
SourceDescription[] userdesclist = new SourceDescription[] {
new SourceDescription(SourceDescription
.SOURCE_DESC_EMAIL,
"jmf-user#sun.com",
1,
false),
new SourceDescription(SourceDescription
.SOURCE_DESC_CNAME,
cname,
1,
false),
new
SourceDescription(SourceDescription.SOURCE_DESC_TOOL, "JMF RTP Player v2.0",
1,
false)
};
mgr.initSession(localaddr,
userdesclist,
0.05,
0.25);
mgr.startSession(sessaddr, ttl, null);
} catch (Exception e) {
System.err.println(e.getMessage());
return null;
}
return mgr;
}
public void update(ReceiveStreamEvent event) {
Player newplayer = null;
RTPPacket playerWindow = null;
// find the sourceRTPSM for this event
SessionManager source = (SessionManager) event.getSource();
// create a new player if a new recvstream is detected
if (event instanceof NewReceiveStreamEvent) {
String cname = "Java Media Player";
ReceiveStream stream = null;
try {
// get a handle over the ReceiveStream
stream = ((NewReceiveStreamEvent) event)
.getReceiveStream();
Participant part = stream.getParticipant();
if (part != null) cname = part.getCNAME();
// get a handle over the ReceiveStream datasource
DataSource dsource = stream.getDataSource();
// create a player by passing datasource to the
// Media Manager
newplayer = Manager.createPlayer(dsource);
System.out.println("created player " + newplayer);
} catch (Exception e) {
System.err.println("NewReceiveStreamEvent exception " +
e.getMessage());
return;
}
if (newplayer == null) return;
playerlist.addElement(newplayer);
newplayer.addControllerListener(this);
// send this player to player GUI
playerWindow = new RTPPacket(newplayer, cname);
}
}
public void controllerUpdate(ControllerEvent evt) {
// get a handle over controller, remove it from the player
// list.
// if player list is empty, close the sesssion manager.
if ((evt instanceof ControllerClosedEvent) ||
(evt instanceof ControllerErrorEvent) ||
(evt instanceof DeallocateEvent)) {
Player p = (Player) evt.getSourceController();
if (!terminatedbyClose) {
if (playerlist.contains(p))
playerlist.removeElement(p);
if ((playerlist.size() == 0) && (mgr != null))
mgr.closeSession("All players are closed");
}
}
}
public void closeManager() {
terminatedbyClose = true;
// first close all the players
for (int i = 0; i < playerlist.size(); i++) {
((Player) playerlist.elementAt(i)).close();
}
if (mgr != null) {
mgr.closeSession("RTP Session Terminated");
mgr = null;
}
}
class RTPPacket extends RTPSourceStream {
public RTPPacket(Player newplayer, String cname) {
// TODO Auto-generated constructor stub
}
}
}