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
Related
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 ).
I've been struggling with the problem of sending continuous data from arduino to Android.
What I want to do is get analog read convert it to 0-5V information, and send that information to Android app.
My arduino code is just simply:
//(...)defining pins and levels
SoftwareSerial BTSerial(rxPin, txPin);
void setup()
{
pinMode(getData, INPUT);
digitalWrite(keyPin, LOW);
BTSerial.begin(9600);
}
void loop()
{
contact = digitalRead(getData);
if (contact == HIGH) {
sensorValue = analogRead(sensorPin);
double voltage = sensorValue * (5.0 / 1023.0);
if (BTSerial.available()) {
Serial.write(BTSerial.read());
}
BTSerial.println(voltage, 3);
BTSerial.write("\r");
if (Serial.available()) {
BTSerial.write(Serial.read());
}
}
delay(5);
}
I need to send data informing about measurment with ~200Hz frequency.
After sending the data to application it seems that part of data is lost.
I tried higher bound rates but the problem still occurs. Is there a way to send continuous data from arduino using serial port without loosing some % of that data?
I think the problem is in the design of the receiver. I Solved BTL communication in .net Xamarin, but the principle should be the same. In Android reading from InputStream must be quick and can not use sleep. You need to use an endless cycle and there quick read data into temp buffer. Immediately a dune bytes to an auxiliary large buffer (use read / write cursor) and then, for example, in timer treat the data (I suppose you are using some packet protocol)
public override void Run()
{
WriteLogInfoToLog("ConnectedThread.Run() - before");
while (true)
{
try
{
int readBytes = 0;
lock (InternaldataReadLock)
{
readBytes = clientSocketInStream.Read(InternaldataRead, 0, InternaldataRead.Length);
Array.Copy(InternaldataRead, TempdataRead, readBytes);
}
if (readBytes > 0)
{
lock (dataReadLock)
{
dataRead = new byte[readBytes];
for (int i = 0; i < readBytes; i++)
{
dataRead[i] = TempdataRead[i];
}
}
}
}
catch (System.Exception e)
{
btlManager.btlState = BTLService.BTLState.Nothing;//Spadlo spojeni, musi spustit cele od zacatku
WriteLogInfoToLog("ConnectedThread.Run() - EXCEPTION " + e.Message + ", " + e.HResult + ", " + e.StackTrace + ", " + e.InnerException);
if (e is Java.IO.IOException)
{
}
else
{
}
break;
}
}
WriteLogInfoToLog("ConnectedThread.Run() - after");
}
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 am working on an Android application that receives a real time data by Bluetooth and plots it on the screen.
The data is a gyro sensor position information. I am sending it from a custom Freescale Kinetis K10 microcontroller board (designed and tested by myself). For the Bluetooth communication I am using HC-05 Bluetooth module.
The format of the data is as follows:
byte_1: position identification byte, always equals to -128
byte_2: position of axis 1
byte_3: position of axis 2
byte_4: position of axis 3
I am sending these 4 bytes continuously one after another, in that particular order. I am sending this packet of 4 bytes every 5 ms and sending the packet takes about 4.7 ms (9600 baud rate).
The data output from the microcontroller is perfect in terms of accuracy and timing (checked with a logic analyzer).
The problem is that when it is being received from the phone, some of the bytes seem to get lost. Here is the part of the code, where I am reading the InputStream:
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e("Printer Service", "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
#Override
public void run() {
Log.i("BluetoothService", "BEGIN mConnectedThread");
byte[] buffer = new byte[4];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
int position = 0;
if(buffer[0] == -128) {
if(bytes >= 2) {
sendArray.errorTilt = buffer[1];
}
if(bytes >= 3) {
sendArray.errorRoll = buffer[2];
}
if(bytes == 4) {
sendArray.errorPan = buffer[3];
}
}
else if(buffer[1] == -128) {
position = 1;
if(bytes >= 3) {
sendArray.errorTilt = buffer[2];
}
if(bytes == 4) {
sendArray.errorRoll = buffer[3];
}
if(bytes >= 2) {
sendArray.errorPan = buffer[0];
}
}
else if(buffer[2] == -128 && bytes >= 3) {
position = 2;
sendArray.errorRoll = buffer[0];
sendArray.errorPan = buffer[1];
if(bytes == 4) {
sendArray.errorTilt = buffer[3];
}
}
else if(buffer[3] == -128 && bytes == 4) {
position = 3;
sendArray.errorTilt = buffer[0];
sendArray.errorRoll = buffer[1];
sendArray.errorPan = buffer[2];
}
if(position <= bytes && bytes > 1) {
sendArray.errorUpdate = true;
}
} catch (Exception e) {
e.printStackTrace();
connectionLost();
BluetoothService.this.stop();
break;
}
}
}
public void write(int oneByte) {
try {
mmOutStream.write(oneByte);
} catch (IOException e) {
Log.e("BluetoothService", "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e("BluetoothService", "close() of connect socket failed", e);
}
}
}
sendArray is a singleton that keeps many different variables.
errorTilt, errorRoll and errorPan are the current values of the axis, which are being updated from the receiving buffer.
"position" keeps the position of the position identification byte. It is used for a check if any variables have been updated.
Many times just one byte is received in the input buffer and since I don't know which axis is that supposed to be, since I don't have information about it's relative position to the position byte, this particular byte is useless and gets lost.
I've tested the accuracy of receiving by the following method. I made the MCU output a triangular wave on one of the axis, instead of the axis data. On the phone the lines of the triangular wave are not straight as they are supposed to be, but randomly curved and containing artifacts.
To plot the data I am using GraphView and I am updating the graph on equal intervals from a separate thread.
I've tried using longer receiving buffer (with a modified receiving algorithm), but this doesn't help as only a few bytes are being received at a time.
I've tried implementing InputStream.available() but it was always giving 127 bytes available, which didn't seem to be true.
I've read many threads about similar problems and I spent the last 5 days working on it, but I couldn't find a good solution.
To summarize, I need to achieve accurate, real time (or close to real time) receiving of all the bytes.
Thread with a similar problem:
How to do good real-time data streaming using Java Android SDK
Thank you.
UPDATE:
I've tried sending the information just for one of the axis, so it is simple and clear, without the need of position bytes. I was sending it again every 5 ms, but this time it was more time between the consecutive bytes, since it's just one byte in the packet.
I used InputStream.read() this time, which doesn't require a buffer. However, the incoming data was corrupted again, because random bytes couldn't be received.
I've seen different project using this method successfully, I don't know why it's not working with me. I thought it might be a problem with the HC-05 Bluetooth module I'm using, but I tried a different one - HC-06, and the situation is the same. I haven't tried a different phone, but my phone (Samsung Galaxy S3, Android 4.1.2) seems to be working OK.
UPDATE2: I've tried again testing the original code with InputStream.available() before reading from the stream.
When the condition is available()>0, there are no major changes, maybe it works slightly worse.
When the condition is available()>1, it never reads. I guess that is because of the unreliable available() method, as it says in the documentation.
you have incorrect processing of data, if you want to get data from microcontroller board. You have to use bytesAvaliable because android bluetooth Socket is pretty slow over microcontroller boards with bluetooth. But "bytesAvaliable way" has nuance - As socket is slow receiver, bytesAvaliable can catch more then 1 packet from board in one time so you gotta devide readed data by yourself, Check my code out below! My code is getting 38 bytes packets from inertial sensor so you gotta only change count of bytes! 0xAA is the first byte of every next packet so if you find 0xAA byte and have 38 bytes you get packet and nullify iterator. But anyway I'm sure that you still can sometimes lose data because it's not high frequency data transfering way
public void run() {
byte[] bytes = new byte[38];
int iterator = 0;
while (true) {
try {
int bytesAvailable = mmInStream.available();
if (bytesAvailable > 0) {
byte[] curBuf = new byte[bytesAvailable];
mmInStream.read(curBuf);
for (byte b : curBuf) {
if (b == (byte) 0xAA && iterator == 38) {
mHandler.obtainMessage(MainActivity.DATA_READ, bytes.length, -1, bytes).sendToTarget();
iterator = 0;
bytes[iterator] = b;
} else {
bytes[iterator] = b;
}
iterator++;
}
}
} catch (IOException ex) {
Log.e(TAG, "disconnected", ex);
connectionLost();
break;
}
}
}