I have a simple sonar arduino project so that it prints the distance every second.
I have implemented an android app using UsbSerial to communicate with my arduino. So far so good, I am able to receive data and the data I receive is correct, but the problem is that the values are sometimes not properly sent.
Here is the sample output I receive:
data: 7
data: 1
data:
data: 71
and here is the code that generates output:
private UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() {
#Override
public void onReceivedData(byte[] arg0)
{
try {
String data = new String(arg0, "UTF-8");
System.out.println("data: " + data);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
};
So in my opinion there is 2 problems here:
Lines 1 & 2 must be just one line with the value of 71
Line 3 should not exists as my application is listening onReceivedData and arduino always send something.
Any help would be much appreciated.
I have found a solution for the issue. by reading this link I noticed that I need to do some manipulation on the data I receive in the onReceivedData method.
So I changed the mCallBack as follow:
private UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() {
#Override
public void onReceivedData(byte[] arg0)
{
if(arg0!= null && arg0.length > 0){
if (isStartByte(arg0[0])) {
printData();
clearBytes();
}
appendBytes(arg0);
}
}
};
and here is the other methods I added:
private void clearBytes(){
buffer=new byte[8];
bufferSize = 0;
}
private void appendBytes(byte[] buf){
System.arraycopy(buf, 0, buffer, bufferSize, buf.length);
bufferSize += buf.length;
}
private void printData() {
if (bufferSize == 0) {
return;
}
byte[] buf = new byte[bufferSize];
System.arraycopy(buffer, 0, buf, 0, bufferSize);
String data = null;
try {
data = new String(buf, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (null != data && !data.isEmpty()) {
System.out.println("data: " + data);
}
}
public boolean isStartByte(byte firstChar){
return firstChar=='A';
}
And also I modified the Arduino code and added character A to the beginning of the serial output.
This solves the issue, however I think this is not the best practice. I think the UsbSerial library should provide better output handling( or maybe I am wrong and this is the nature of working with serial communication ).
Related
I'm try to send and receive data between Android device and Arduino Mega 2560 via bluetooth low energy bt-410,
When I receive data type is byte[] and I decode to string it's a question symbol so I try to Log byte[] convert to byte and then value is -32, and when I send some string from my app to Serial Monitor in Arduino is nothing.
how can I send and receive data?
//Receive data:
#Override
public void onCharacteristicChanged(BluetoothGatt mGatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(mGatt, characteristic);
String textRX;
try {
textRX = new String(characteristic.getValue(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
writeLine("Received: " + textRX);
hideKeyboard();
scrollDown();
}
//Send data:
public void sendClick(View view) {
String message = editInput.getText().toString();
if (tx == null || message.isEmpty()) {
return;
}
try {
value = message.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
tx.setValue(value);
if (mGatt.writeCharacteristic(tx)) {
writeLine("Sent: " + message);
editInput.setText("");
hideKeyboard();
scrollDown();
Log.e("textTX", tx + "");
} else {
writeLine("Couldn't write TX characteristic!");
}
}
//Arduino Code:
String inputString="";
void setup() {
Serial.begin(9600);
}
void loop() {
if(Serial.available() > 0) {
inputString = Serial.readStringUntil('\n');
Serial.println(inputString);
if (inputString == "R1") {
delay(100);
Serial.println("R1 on");
}
}
delay(10);
}
Bytes in Java are signed, not the most bone-headed decision I've ever seen but it comes close. There are possibly use cases where it makes sense to treat it as signed, but I can't think of any off the type of my head. I probably would have preferred an unsigned byte type, using a type like shorter as the signed variant :-)
In any case, that means that getting a value greater than 127 from your comms channel is going to look like a negative number to Java.
More precisely, it will look like unsignedEquivalent - 256 and that should therefore provide you the clue on how to "fix" it.
Take your byte, put it into a wider data type (such as int), then add 256:
byte bdata = -32; // should have been 224
int idata = bdata;
idata + 256; // is 224
I am developing Client-Server application in C++ using Qt framework, but the clients can be android phones and computers(Qt client app)
Now i'm having troubles to handle Reception of data on the server side; the server is not receiving data properly.
First, I got things working nicely between the server(Qt app) and the client(Qt app) using these methods for sending and receiving:
The size of the message is kept at the beginning of the packet to help check whether the whole message is received or not.
This is the method to send message to the clients
void Server::send(const QString &message)
{
QByteArray paquet;
QDataStream out(&paquet, QIODevice::WriteOnly);
out << (quint16) 0; // just put 0 at the head of the paquet to reserve place to put the size of the message
out << message; // adding the message
out.device()->seek(0); // coming back to the head of the paquet
out << (quint16) (paquet.size() - sizeof(quint16)); // replace the 0 value by the real size
clientSocket->write(paquet); //sending...
}
This slot is called every time a single paquet is received.
void Server::dataReceived()
{
forever
{
// 1 : a packet has arrived from any client
// getting the socket of that client (recherche du QTcpSocket du client)
QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
if (socket == 0)
return;
QDataStream in(socket);
if (dataSize == 0) // if we don't know the size of data we are suppose to receive...
{
if (socket->bytesAvailable() < (int)sizeof(quint16)) // we haven't yet receive the size of the data completly then return...
return;
in >> dataSize; // now we know the amount of data we should get
}
if (socket->bytesAvailable() < dataSize)
return;
// Here we are sure we got the whole data then we can startreadind
QString message;
in >> message;
//Processing....
dataSize = 0; // re-initialize for the coming data
}
}
This is working well when the server is talking with the Qt app Client, because the same methods are used there, and the size of quint16 will remain the same hover it doesn't work with android client, then i tried another way in which i wanted to ignore the size of the message sent, but format the message in a way such that i can know where it starts and where it ends, then with some controls i can get it however i'm stuck here, cause the data read doesn't contain anything when printed, but his size has a value(which even vary according to the amount of text the client send)!
void Server::dataReceived() // a packet is received!
{
QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
if (socket == 0)
return;
QByteArray data= socket->readAll(); //reading all data available
QString message(data)
qDebug() << data; // this prints nothing!
qDebug() << data.size();// But this prints a non null number, wich means we got something, and that number varies according to the amount of text sent!
qDebug() << message; // this also prints notghing!
}
PS: it's not working even for the Qt app Client.
Can you help me find out what's wrong, i'm a bit confused how the tcp protocol is handling the data, and if you could and also advise me a good way for doing this.
here is the android class I made for the purpose
class QTcpSocket implements Runnable {
private String ip="";
private int port;
private Socket socket;
private PrintWriter printWriter;
private DataOutputStream dataOutputStream;
private DataInputStream dataInputStream;
public QTcpSocket(String ip, int port) {
this.ip = ip;
this.port = port;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getIp() {
return this.ip;
}
public void setPort(int port) {
this.port = port;
}
public void run() {
try {
socket = new Socket(this.ip, this.port);
dataOutputStream = new DataOutputStream( socket.getOutputStream() );
dataInputStream = new DataInputStream(socket.getInputStream());
String response = dataInputStream.readUTF();
dataOutputStream.writeUTF("Hello server!");
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMessage(String message) {
try {
dataOutputStream.writeUTF(message);
}catch (IOException e) {
e.printStackTrace();
}
}
public void disconnect() {
try {
printWriter.flush();
printWriter.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean isClosed() {
return socket.isClosed();
}
}
Replace in 'data' all bytes with value 0 by value 20 and print again. I think you see nothing printed because the first byte is 0. You could also replace with 'X'. Did you already replace writeUTF() by write() ?
20 is the space character. But then you also see nothing printed so better use a X char. Strings get printed until a \0 char (which indicates the end of a string) is met. Because nothing was printed i supposed one right at the beginning. So writeUTF causes that leading 0. I could only explain that if all chars had doubled. What was the first char you sent?
But now: send size-of-message first so it equals your qt client.
My code is starting to get a bit hard to debug which leads me to believe that my design choices are not ideal. I am a novice Android programming and would love some help with streamlining the design for optimum operation.
Intro
I am writing an application that uses rfcomm interface to transfer data between a client and server device. The client needs to request certain things from the server using a specific key, then it needs to wait until the server sends the result back.
Current Design
A button press triggers a request for information from the server.
A new thread is started which performs the request.
A key which is a unique integer is converted to a byte array and sent to the server.
Thread has a while loop that is waiting for a specific boolean to flip from false to true indicating a response back from the server.
Information is received on the server side. Server uses key to identify what to do next.
server starts a thread to run some query and gets a jsonString back as a result.
Server sends jsonstring converted to byte array prepended with the same identifying key back to the client.
Client reads message, and sends the byte array to a handling method based on the identifying key.
Handling method stores jsonString to a class variable and then flips the boolean to let the other thread know that the value it was waiting on has been set.
Json string is converted to object on the client side. Something is done with that object.
This code currently correctly sends info to the server, server correctly does search and gets a valid json string result. However, the issue occurs when the server writes its results make to the client. I am getting 20 messages instead of one and none match the search key...
My questions
Am I doing things in an efficient way design wise?
Can I benefit from using synchronized keyword or and Atomic Boolean to make my code more thread safe? How would I go about implementing it?
Is there a max length for converting strings to byte array? Maybe the code is trying to break up the sending for me and that's why I'm getting 20 different results?
Relevant code
public class ClientSpokesmanClass {
private final int searchKey = 2222222; //set the key to some int.
private boolean pendingSearchResults = false;
List<Place> places = new ArrayList<Place>();
private final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg){
switch(msg.what) {
...
case MESSAGE_READ:
//Message received from server
readAndDistribute(msg.arg1, msg.obj);
break;
...
}
}
};
public List<Place> getPlacesFromServer(String query){
//ask server for search results
requestSearchFromServer(query);
//just wait for them...
while (pendingSearchResults){
//just waiting
}
return places;
}
private void requestSearchFromConnectedDevice(String query) {
if (mBluetoothState == STATE_CONNECTED){
byte[] bites = new byte[4];
bites = ByteBuffer.wrap(bites).putInt(searchKey).array();
byte[] stringBytes = null;
try {
stringBytes = query.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
Log.e(TAG, "unsupported encoding", e);
}
int keyLength = bites.length;
int stringLength = stringBytes.length;
byte[] combined = new byte[keyLength+stringLength];
System.arraycopy(bites, 0, combined, 0, keyLength);
System.arraycopy(stringBytes, 0, combined, keyLength, stringLength);
mBluetoothService.write(combined);
}
pendingSearchResults = true;
}
private void receiveSearchResults(byte[] bites){
String jsonString = "";
PlacesJSONParser parser = new PlacesJSONParser();
try {
jsonString = new String(bites, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
Log.e(TAG, "unsupported encoding", e);
}
if (D) Log.d(TAG, "Json string we got is "+jsonString);
try {
places = parser.parse(new JSONObject(jsonString));
} catch (JSONException e) {
// TODO Auto-generated catch block
Log.e(TAG, "JSON exception", e);
}
pendingSearchResults = false;
}
/**
* Reads come here first. Then, based on the key prepended to them,
* they then go to other methods for further work.
* #param bytes
* #param buffer
*/
private synchronized void readAndDistribute(int bytes, Object buffer){
byte[] buff = (byte[]) buffer;
int key = ByteBuffer.wrap(Arrays.copyOfRange(buff, 0, 4)).getInt();
if (key == searchKey){
receiveSearchResults(Arrays.copyOfRange(buff, 4, bytes));
}else{
//do something else
}
}
}
.
public class ClientUI extends Activity {
...
onQueryTextSubmit(String query){
final String queryFinal = query;
Thread thread = new Thread(){
public void run() {
places = ClientSpokesmanClass.getPlacesFromServer(query);
doSomethingWithPlaces();
}
};
thread.start();
}
}
.
public class ServerReceive {
private searchKey = 2222222;
...
//code that handles messages, reads key, and then runs doSearchAndWriteResults()
...
private synchronized void doSearchAndWriteResults(byte[] bites){
if (D) Log.d(TAG, "+++writeSearchResults");
//Initialize query and placesString
String query = null;
String placesString;
//Convert byte array to the query string
try {
query = new String(bites, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
Log.e(TAG, "unsupported encoding",e);
}
//if the string was converted successfully...
if (query != null){
//Run the places query and set the json string to placesString
if (D) Log.d(TAG, "query is "+query);
PlacesProvider placeProvider = new PlacesProvider();
placesString = placeProvider.getPlacesString(query);
}
//initialize a bite array
byte[] stringBytes = null;
try {
//convert jsonString to byte array
stringBytes = placesString.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
Log.e(TAG, "unsupported encoding",e);
}
//Put the search key to a byte array. I am using this key on the client side
//to confirm that we are reading searchResults and not some other type of write.
byte[] bite = new byte[4];
bite = ByteBuffer.wrap(bite).putInt(searchKey).array();
//Get the lengths of the two byte arrays
int keyLength = bite.length;
int stringLength = stringBytes.length;
//combine the byte arrays for sending
byte[] combined = new byte[keyLength+stringLength];
System.arraycopy(bite, 0, combined, 0, keyLength);
System.arraycopy(stringBytes, 0, combined, keyLength, stringLength);
if (D) Log.d(TAG, "Actually writing things here...");
//send the byte arrrays over rfcomm
mBluetoothService.write(combined);
}
}
Take a look at https://github.com/gettyimages/connect_sdk_java. Specifically, at the test application. It performs a search using an AsyncTask and the private class notifies the UI via onPostExecute. Hopefully, this will get you further along.
I'm sorry if this is a very general question but I don't know where to start so I'm looking for ideas.
I have a windows app (music score editing) and I'm currently porting it to Andriod which is coming along well.
I would like to add the feature than documents created in the windows app can be sent to the users android tablet. I was wondering, how would I write some kind of listener on Android that the windows side could open a socket or something to and send data across to it, assuming both are on the same local network.
thanks
I think sending files directly over a local network isn't the best approach. You are prone to many user complaints that the sharing isn't working.. and this will mostly be due to their own network configuration issues.
Why not use a service like DropBox to implement file sharing?
Services like DropBox offer simple API that can be used in apps in order to save files into a remote folder, and read files from a remote folder.
This way, users will not have to be in the same network at all.. and most of the heavy-lifting of implementing file sharing will be done by a service that is focused around that.
Addition:
If you don't want to require an account for a separate service like DropBox, consider this approach: Implement a very simple DropBox-like service on your own web server. Make a simple script that will allow users to upload a file to your server anonymously via HTTP. After upload, they will receive a 5 digit id for this file, or some other link they could share. When using this id or link from the 2nd app, the file could be downloaded (again via HTTP). If you delete files automatically from the server after a few hours, you will not run out of space.
You can implement such a service with about 20 lines of PHP code. And the required apps code is extremely simple (since it only relies on HTTP). If you're worried about the costs of a web server, you can get one from about $5/month or even use a free service like Google App Engine (free if your bandwidth+space requirements are low).
Code example for the file upload. Downloading should be simple enough to do alone. Regarding the periodical file delete - the obvious approach is cron but I think it's easy to manage without it. Whenever you accept a new upload (in the PHP script), go over all the downloads and delete old ones.
i wrote a small thing so my windows app can find an instance of my android app running on the local network, here it is. this is the android code first
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import android.os.AsyncTask;
import android.util.Log;
public class TabSyncServer extends AsyncTask<Void, Void, Void> {
ServerSocket mServerSocket = null;
Socket mSocket = null;
DataInputStream mDataInputStream = null;
DataOutputStream mDataOutputStream = null;
#Override
protected void onPreExecute() {
try {
mServerSocket = new ServerSocket(2112);
//System.out.println("Listening :2112");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
protected Void doInBackground(Void... args) {
byte[] bytebuf = new byte[1024];
while (true) {
try {
mSocket = mServerSocket.accept();
mDataInputStream = new DataInputStream(mSocket.getInputStream());
mDataOutputStream = new DataOutputStream(mSocket.getOutputStream());
Log.d("TabSyncServer", "ip: " + mSocket.getInetAddress());
mDataInputStream.read(bytebuf);
String str = new String(bytebuf, "UTF8");
Log.d("TabSyncServer", "message: " + str);
if(str.contains("Hello Android")) {
Log.d("TabSyncServer", "sending reply");
mDataOutputStream.writeBytes("Hello Windows");
}
//
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (mSocket != null) {
try {
mSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (mDataInputStream != null) {
try {
mDataInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (mDataOutputStream != null) {
try {
mDataOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
and the windows MFC code
void CMainFrame::OnBrowseMobile() {
CMobileSync* con = new CMobileSync();
CString ipaddr_base;
int my_last_digit;
if(!con->getMyIP(ipaddr_base, my_last_digit)) {
setMobilePath("Can't find local network");
return;
}
for(int i=1 ; i<98 ; i++) {
if(i==my_last_digit)
continue; // don;t check self
CString ipaddr; ipaddr.Format("%s.%d", ipaddr_base, i);
bool res = con->ConnectToHost(ipaddr);
if(res) {
res = con->SendMsg ("Hello Android");
if(res) {
TRACE1("send ok %s\n",ipaddr.GetBuffer());
#define RD_BUF_LEN 80
char buffer[RD_BUF_LEN];
if(con->ListenOnPortBlocking(buffer, RD_BUF_LEN)) {
if(strncmp(buffer, "Hello Windows", 12)==0) {
TRACE1("reply ok %s", buffer);
setMobilePath(ipaddr);
con->CloseConnection ();
return;
}
}
} else {
TRACE("send FAILED\n");
}
}
con->CloseConnection ();
}
setMobilePath("No TabTrax on local network");
}
#include "stdafx.h"
#include <winsock.h>
#include "MobileSync.h"
#define TTPORT 2112
bool CMobileSync::getMyIP(CString& ipaddr_front, int& ipaddr_lastdigit)
{
char szBuffer[1024];
#ifdef WIN32
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 0);
if(::WSAStartup(wVersionRequested, &wsaData) != 0)
return false;
#endif
if(gethostname(szBuffer, sizeof(szBuffer)) == SOCKET_ERROR)
{
#ifdef WIN32
WSACleanup();
#endif
return false;
}
struct hostent *host = gethostbyname(szBuffer);
if(host == NULL)
{
#ifdef WIN32
WSACleanup();
#endif
return false;
}
//Obtain the computer's IP
unsigned char b1, b2, b3, b4;
b1 = ((struct in_addr *)(host->h_addr))->S_un.S_un_b.s_b1;
b2 = ((struct in_addr *)(host->h_addr))->S_un.S_un_b.s_b2;
b3 = ((struct in_addr *)(host->h_addr))->S_un.S_un_b.s_b3;
b4 = ((struct in_addr *)(host->h_addr))->S_un.S_un_b.s_b4;
ipaddr_front.Format("%d.%d.%d", b1, b2, b3);
ipaddr_lastdigit = b4;
#ifdef WIN32
WSACleanup();
#endif
return true;
}
//CONNECTTOHOST – Connects to a remote host
bool CMobileSync::ConnectToHost(const char* IPAddress)
{
//Start up Winsock…
WSADATA wsadata;
int error = WSAStartup(0x0202, &wsadata);
//Did something happen?
if (error)
return false;
//Did we get the right Winsock version?
if (wsadata.wVersion != 0x0202)
{
WSACleanup(); //Clean up Winsock
return false;
}
//Fill out the information needed to initialize a socket…
SOCKADDR_IN target; //Socket address information
target.sin_family = AF_INET; // address family Internet
target.sin_port = htons (TTPORT); //Port to connect on
target.sin_addr.s_addr = inet_addr (IPAddress); //Target IP
mSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); //Create socket
if (mSocket == INVALID_SOCKET)
{
return false; //Couldn't create the socket
}
//Try connecting...
if (connect(mSocket, (SOCKADDR *)&target, sizeof(target)) == SOCKET_ERROR)
{
return false; //Couldn't connect
}
return true; //Success
}
//CLOSECONNECTION – shuts down the socket and closes any connection on it
void CMobileSync::CloseConnection ()
{
//Close the socket if it exists
if (mSocket)
closesocket(mSocket);
mSocket=0;
WSACleanup(); //Clean up Winsock
}
int CMobileSync::SendMsg (char* szpText, int buflen)
{
if(buflen==0)
buflen = strlen(szpText);
int ret = send(mSocket, szpText, buflen, 0);
TRACE1("CMobileSync::SendMsg sent %d bytes\n", ret);
return ret;
}
WSADATA w;
//LISTENONPORT – Listens on a specified port for incoming connections
//or data
bool CMobileSync::ListenOnPortBlocking(char* buffer, int buflen)
{
//Now we can start listening (allowing as many connections as possible to
//be made at the same time using SOMAXCONN). You could specify any
//integer value equal to or lesser than SOMAXCONN instead for custom
//purposes). The function will not //return until a connection request is
//made
// listen(s, SOMAXCONN);
memset(buffer, 0, sizeof(buffer)); //Clear the buffer
int iTimeout = 1600;
setsockopt( mSocket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&iTimeout, sizeof(iTimeout));
//Put the incoming text into our buffer
int ret = recv (mSocket, buffer, buflen-1, 0);
//Don't forget to clean up with CloseConnection()!
if(ret != SOCKET_ERROR)
return true;
int err = WSAGetLastError();
return false;
}
its not tested extensively but it is running
this maybe useful to someone
I have been using InputStream.read( byte[] b, int off, int len ) method to read in data, but now have run into a timeout problem. I am sometimes expecting timeouts from reading, and should have the program adjust itself accordingly after a timeout. I have tried to implement a Thread but I really know nothing about Threads and cannot get it to work. I also want to add that this thread is being initialized within another thread. I'm not sure what the implications of this are but it may cause a problem.
My initial code had worked for the majority of times I need to read, but whenever I'm expecting a timeout, my program freezes at the read() call and never times out. When I implemented this new code, the times when my initial code worked now time out. I use Thread.wait(500) which I assume is 500 milliseconds, but I cannot find any Javadocs including the wait() function. Here and Here.
Other posts relating to this: 1, 2, 3.
I have also looked into declaring a timeout for the BluetoothSocket, but I cannot find it anywhere in the documentation.
Here is what my initial code looks like:
public void run(int length) throws IOException {
buffer = new byte[1024];
try {
bytes = mmInStream.read(buffer, 0, length);
mHandler.obtainMessage(MainMenu.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Message msg = mHandler.obtainMessage(MainMenu.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString( TOAST, "Device has disconnected from the Bluetooth Module." );
msg.setData(bundle);
mHandler.sendMessage(msg);
connectionLost();
BluetoothService.this.start();
}
This is what I have tried to implement:
public void run(int length) throws IOException {
buffer = new byte[1024];
length1 = length;
Thread myThread = new Thread(new Runnable() {
public void run() {
try {
bytes = mmInStream.read( buffer, 0, length1 );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
synchronized (myThread) {
myThread.start();
try {
myThread.wait(500);
if(myThread.isAlive()) {
mmInStream.close();
Log.i( "InStream", "Timeout exceeded!");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
myThread.run();
mHandler.obtainMessage(MainMenu.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Message msg = mHandler.obtainMessage(MainMenu.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString( TOAST, "Device has disconnected from the Bluetooth Module." );
msg.setData(bundle);
mHandler.sendMessage(msg);
connectionLost();
BluetoothService.this.start();
}
EDIT:
So I'm trying to recreate
buffer = new byte[1024];
bytes = mmInStream.read(buffer, 0, length);
I have done the following:
Scanner scan = new Scanner(new InputStreamReader(mmInStream));
String readIn;
try {
readIn = scan.next();
bytes = 5; // I tried with or without this, since I do not think it matters...
buffer = readIn.getBytes( Charset.forName( "US-ASCII" ) );
}
Later in my code I make this call....Sorry edit again, the buf=read( 5 ) call goes to what is shown above.
byte[] buf = buffer;
write( a );
buf = read( 5 );
Log.i(TAG, "Before buf[5]" );
try {
buf[5] = '\0';
} catch( NullPointerException e ) {
return false;
}
When I use the original method, It passes this buf[5] call fine. But when I use the new method, it gives me an IndexOutOfBoundsException at that spot. Am I missing something? The expected input should be CMD\r\n
The bluetooth chat example is really poor in this respect, you should use an input scanner instead of mmInStream.read. Here's what I use and it works reasonably well...
For your use case you skip the entire buffer and byte and write and read (no need to use any of those when you are using a scanner and inputstreamreader as those handle that stuff for you)... in other words the below code takes care of all that for you. I changed the delimiter for you to CRLF. What the code below does is you send a string and it writes it and then reads. If you don't need to send anything to the remote device, just start at scan = new Scanner. Each time a line is read and it ends with \r\n it will store it in the string instring.
So if you want to send "a", you would write
String readIn = beginListenForData("a");
The a will be sent under the mmOutStream and then the scanner will read the mmInStream and collect all the characters, then once it sees a CRLF it will return the characters it read and return them in your readIn string. Make sense?
private String beginListenForData(String msg0) {
msg0 += "\r"; //this adds a return character to the string, you can omit this if you just send an a and the remote device understands what that means.
String instring = "";
try {
mmOutStream.write(msg0.getBytes());
} catch (IOException ex) {
stop();
}
scan = new Scanner(new InputStreamReader(mmInStream));
scan.useDelimiter(Pattern.compile("[\\r\\n]+"));
instring = scan.next();
scan = null;
return instring;
}