I am working on a simple app for the android OS. It needs to reliably communicate with the Arduino Uno. I used the USBSerialDriver with AndroidStudio. I'm getting data but there are dropped characters. my code below. I get the same result when i use apps available on Google Play. Except for one app that does work the Arduino-Communicator. The only thing i guess is that in the Arduino-Communicator they set some setup bytes to the driver to configure the Arduino interface. Is this possible using the libraries i currently use below?
// Get UsbManager
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
// Find the first available driver.
UsbSerialDriver arduinoDrv = UsbSerialProber.acquire(manager);
// setup serial port
if (arduinoDrv != null) {
// establish connection
try {
arduinoDrv.open();
} catch (IOException e) {
e.printStackTrace();
}
try {
arduinoDrv.setBaudRate(9600);
} catch (IOException e) {
e.printStackTrace();
}
try {
numBytesRead = arduinoDrv.read(rxBuff, 500);
} catch (IOException e) {
e.printStackTrace();
}
rxBuff[numBytesRead]=0;
this is the code in the Arduino-Communicator. I just don't know if it will help the drop packet and how to implement it using the USBSerialdriver above.
// Arduino USB serial converter setup
// Set control line state
mUsbConnection.controlTransfer(0x21, 0x22, 0, 0, null, 0, 0);
// Set line encoding.
mUsbConnection.controlTransfer(0x21, 0x20, 0, 0, getLineEncoding(9600), 7, 0);
thanks!
Related
I am trying to control/operate a motor from an android phone in "as close as possible" realtime using the Android SPP Bluetooth socket interface. The motor ought to run in a so called 'dead man' operation mode. So the motor will only turn if a button on the android APP is touched and ought to stop immediately if the touch is released.
I implemented this by continuously sending 'keep turning' telegrams of 20 Bytes about every 20ms to keep the motor turning and to have the motor stop immediately as soon as no more telegrams are received or if a STOP telegram is received.
This seem to work acceptable well on some phone but others continue sending 'keep turning' telegrams even after the MotionEvent.ACTION_UP event has been processed and no more data are being send.
I assume that this is caused by some internal buffers that cache the transmit data and continue sending until the buffer is empty.
Simple questions:
Is there a way to purge the BT stream transmit buffer to stop all data transfer immediately?
Or can I get the fill level of the transmit buffer in which case I would not put anything more than about 2 telegrams into it?
Or is there a way to specify the buffer size when opening the stream?
Searching the net, I was not able to find anything that talks about BT stream buffer size of buffer management.
And Yes, I have implemented read and write functions as threads and I do not have any problems in reading all telegrams, and I do not need to deliver telegrams in real time but I should be able to stop sending 'keep turning' telegrams within about 50 to 100ms.
Any hints are very welcome.
I am sorry that I did not add the code, I thought it may not be necessary as it is straight forward as:
#Override
public boolean onTouch(final View v,MotionEvent event) {
int eventAction = event.getAction();
switch (eventAction) {
case MotionEvent.ACTION_DOWN:
if (v == btnUp || v == btnDown) {
// Start a thread that sends the goUP or DOWN command every 10 ms until
// btnUp released
tvCounter.setText("----");
action_touched = true;
new Thread(new Runnable() {
#Override
public void run() {
int counter = 1;
// Disable heart beat
ServiceRequest.send(EnRequest.REQ_SET_HEARTBEAT,0);
// Send GoUp command plus a wrapping counter byte every nn ms
// until the button is released
while (action_touched) {
try {
setDeadmanMove(v==btnUp,counter);
Thread.sleep(20);
++counter;
}
catch (InterruptedException ex) {
action_touched = false;
}
catch (Exception ex) {
action_touched = false;
}
}
// Send a STOP command
setDeadmanStop();
// Enable heart beat again
ServiceRequest.send(EnRequest.REQ_SET_HEARTBEAT,1);
// We are done
}
}).start();
}
break;
case MotionEvent.ACTION_UP:
// Stop Thread
action_touched = false;
break;
}
return true;
}
The snipped below is part of the communication class that manages the Bluetooth serial communication.
public void btWrite(DeviceRecord message) {
if (runBTreceiver) {
if (message.isValidRecord()) {
try {
lock.lock();
++lockCounter;
mmBufferedOut.write(message.getFullRecord());
mmBufferedOut.flush();
}
catch (IOException e) {
if (GlobalData.isDebugger) Log.i(TAG, "Failed sending " + message + " " + e.getMessage());
ServiceResponse.send(EnEvent.EVT_BT_RECEIVER_ERROR, "Error data send: " + e.getMessage());
resetConnection();
runBTreceiver=false;
}
finally {
--lockCounter;
lock.unlock();
}
}
}
}
The code snipped that allocates and opens the Bluetooth connection
try {
// Set up a pointer to the remote node using it's address.
BluetoothDevice device = myBluetoothAdapter.getRemoteDevice(myBluetoothMacId);
if (device != null)
{
// Two things are needed to make a connection:
// A MAC address, which we got above.
// A Service ID or UUID. In this case we are using the
// UUID for SPP.
try {
myBluetoothSocket = device.createRfcommSocketToServiceRecord(GlobalData.MY_UUID);
}
catch (IOException e) {
sendEventStatus(EnEvent.EVT_BTADAPTER_FAIL,
String.format(GlobalData.rString(R.string.srv_failcrt),BTERROR_CREATE,e.getMessage()));
}
// Establish the connection. This will block until it connects or
// timeout?
try {
if (! myBluetoothSocket.isConnected()) {
myBluetoothSocket.connect();
}
}
catch (IOException e) {
try {
Log.e("","trying fallback...");
myBluetoothSocket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);
myBluetoothSocket.connect();
}
catch (IOException e2) {
sendEventStatus(EnEvent.EVT_BTADAPTER_FAIL,e2.getMessage());
}
}
}
else {
sendEventStatus(EnEvent.EVT_BTADAPTER_FAIL,
String.format(GlobalData.rString(R.string.srv_failcrt),BTERROR_DEVICE,"getRemoteDevice failed"));
}
}
catch (Exception e) {
sendEventStatus(EnEvent.EVT_BTADAPTER_FAIL, e.getMessage());
return;
}
InputStream tmpIn = null;
OutputStream tmpOut = null;
mmSocket = socket;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
}
catch (IOException e) {
ServiceResponse.send(EnEvent.EVT_ERROR, GlobalData.rString(R.string.srv_failcst) + e.getMessage());
resetConnection();
runBTreceiver=false;
}
mmInStream = tmpIn;
// mmOutStream = tmpOut;
mmBufferedOut = new BufferedOutputStream(tmpOut,80);
// Initial request
btWrite(new DeviceRecord(0, 4));
I have never discovered any problems sending and receiving data via this code. All records are sent and received properly. Only problem was that I am unable to purge the transmit buffer at the moment the operate button was released.
To overcome this problem, I have changed the protocol in such a way, that only a single 'keep turning' telegram is send at a time, the next telegram will be send after a response from the other end (sort of handshaking), the program then continue to run this ping/pong until the button is released.
This method works quite well as the transmit buffer will never hold more than one telegram at a time.
the mentioned problem is solved though but I still have no clue of whether it would be possible to purge a transmit buffer
I am creating a app where videos are played in T.v by connecting the android device to T.v through HDMI cable.I want detect if T.V is turned off using the HDMI cable.I also tried a method mentioned in this link but its not working.
How to check the HDMI device connection status in Android?
Get the data file from the location /sys/class/display/display0.hdmi/connect.If the data in the file is 0 hdmi is not connected if its 1 its connected.Try this method.
try
{
File file = new File("/sys/class/display/display0.hdmi/connect")
InputStream in = new FileInputStream(file);
byte[] re = new byte[32768];
int read = 0;
while ( (read = in.read(re, 0, 32768)) != -1)
{
String string="Empty";
string = new String(re, 0, read);
Log.v("String_whilecondition","string="+string);
result = string;
}
in.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
I have done a simple app to connect my phone with an Arduino via BT and all goes right. My phone have Android 2.3.6... But, when I try the app on my tablet (with android 4.0.3), I can't connect. I post here the specific piece of code:
try {
BluetoothSocket socket = mydevice.createRfcommSocketToServiceRecord(UUID.fromString(ARDUINO_STANDAR_UUID));
socket.connect();
OutputStream output = socket.getOutputStream();
InputStream input = socket.getInputStream();
Log.d(TAG, "Connected");
}
catch (IOException e) { Log.e(TAG, e.getMessage()); }
}
Using the Log, the problem is at socket.connect(); at that point, I have to enter the PIN of the device, but it don't connect anyway... The error is "Connection refused"...
What can be wrong?
Try something like this to take care of the connection. I just updated an old android-10 app the other day to android-17 and dealt with exactly this.
BluetoothDevice yourDevice;
try {
Method m = yourDevice.getClass().getMethod( "createInsecureRfcommSocket", new Class[] { int.class } );
selectedDeviceSocket = (BluetoothSocket) m.invoke( yourDevice, Integer.valueOf( 1 ) );
selectedDeviceSocket.connect();
}
I'd like to print an image from my sd card with a Zebra EM220. I tried to use
GraphicsUtil.printImage("image path", 0, 0)
but all my attempts failed and I'm just able to print a list of characters.
In a first time, I tried to use that :
ZebraPrinter zp = ZebraPrinterFactory.getInstance(printerCo);
zp.getGraphicsUtil().printImage(path, 0, 0);
But the result was a ZebraLanguageUnknownException.
So I followed this solution : https://km.zebra.com/kb/index?page=content&id=SO8239&actp=LIST_RECENT but just a list of characters was printed.
I have no idea how to solve the problem so if someone succeeded to print an image with the Zebra EM 220 and can share the code, it should help me.
My code :
public void print(){
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myimage.jpg";
ZebraPrinterConnection printerCo = new BluetoothPrinterConnection(printerMacAdress);
try {
printerCo.open();
if (printerCo.isConnected()){
ZebraPrinter zp = new ZebraPrinterCpcl(printerCo);
zp.getGraphicsUtil().printImage(path, 0, 0);
Thread.sleep(500);
}
} catch (ZebraPrinterConnectionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try{
// Close the connection to release resources.
printerCo.close();
} catch (ZebraPrinterConnectionException e) {
e.printStackTrace();
}
}
}
}
Are you using the ZebraLink SDK? If so, it does not support the EM220. The ZebraLink SDK is designed for use with CPCL and ZPL printers. You can see the list of supported printers here: (click the compatible printers link in the middle): http://www.zebra.com/us/en/products-services/software/adapt-software/zebralink-sdk-android.html#mainpartabscontainer_71ac=downloads.
For the EM 220, you should instead use Zebra's EM 220 SDK for Android (bottom link): http://www.zebra.com/us/en/support-downloads/mobile/em-220.html.
And here is a quick piece of sample code (from Zebra's knowledgebase) explaining one method of printing through this SDK to an EM 220: https://km.zebra.com/kb/index?page=answeropen&type=open&searchid=1363808738897&answerid=16777216&iqaction=5&url=https%3A%2F%2Fkm.zebra.com%2Fkb%2Findex%3Fpage%3Dcontent%26id%3DSA316%26actp%3Dsearch%26viewlocale%3Den_US&highlightinfo=4194576,157,181#.
I'm developing a UDP responder to handle basic SSDP commands. The purpose of this piece of code is to do auto discovery, so when the server sends a multicast to a specific group all other subscribed devices should send back a UDP packet announcing its presence to the host and port of who sent the multicast. My android device receives and sends the packet just fine but because it takes too long to get back the SocketAddress object from getSocketAddress() method the server times out, closes the listening port and never gets a packet back from the android device.
Here's my code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MulticastSocket ms = null;
byte[] packBuf = new byte[128];
try {
ms = new MulticastSocket(32410);
ms.joinGroup(InetAddress.getByName("239.255.255.250"));
} catch (IOException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
while (true)
{
DatagramPacket receivedPack = new DatagramPacket(packBuf, packBuf.length);
try {
ms.receive(receivedPack);
Log.d(TAG, "Received data");
} catch (IOException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
String responseStr = "HTTP/1.0 200 OK\n" +
"Content-Type: app\n" +
"Resource-Identifier: 945e7dd5913ab45f1db4f271a1620b9471fb7d4d\n" +
"Name: Test App\n" +
"Port: 8888\n" +
"Updated-At: 1319511680\n" +
"Version: 0.9.3.4-29679ad\n" +
"Content-Length: 23\n\n" +
"<message>test</message>";
byte[] response = responseStr.getBytes();
DatagramSocket sendSocket = null;
try {
sendSocket = new DatagramSocket();
} catch (IOException e2) {
// TODO Auto-generated catch block
Log.e(TAG,"Erro",e2);
}
DatagramPacket outPack;
try {
outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getSocketAddress());
sendSocket.send(outPack);
} catch (UnknownHostException e1) {
Log.e(TAG,"Erro",e1);
}
catch (IOException e) {
Log.e(TAG,"Erro",e);
}
catch (Exception e)
{
Log.e(TAG,"Erro",e);
}
}
}
Any ideas?
thanks in advance,
fbr
The most likely problem is that getSocketAddress() is trying to resolve the DNS name of the IP address, which is timing out either due to it being a multicast address or just general DNS lag.
The InetSocketAddress class has a constructor option needResolved which can control this behavior. Unfortunately, it does not appear that DatagramPacket.getSocketAddress() allows you to specify that you want that set to false.
This is apparently a known issue, with some recent discussion of it here:
Issue 12328: DatagramChannel - cannot receive without a hostname lookup
The thread suggests that this has been fixed in Android 3.0, and offers a couple of workarounds for Android 2.0 which may or may not work.
In your case, you could try creating an InetSocketAddress set to INADDR_ANY and port 0 with needsResolved set to 0, and then pass that in when you create receivedPack. Hopefully receive() will reuse that and remember the setting.
2 things come to mind...
1) What happens when you change:
outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getSocketAddress());
to
outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getAddress(), receivedPack.getPort());
2) I remember having this sort of problem with an embedded Java on a Home Automation system. Our short term solution was to put most of the machine and multicast addresses in the hosts file. Long term we ended up with a local DNS server.
There is a parameter somewhere in the Java Network stack that tells it how long to cache DNS failures in memory. We cranked that number up to, I think, 5 minutes instead of 10 seconds.