I'm trying to build an application that reads information sent on a bluetooth service using rfcomm.
The device is an hardness tester (HT-6510A), unfortunalty specs about the device data format can't be found I'm faced with a strange problem, I've to understand how to read these information.
01-11 17:47:28.940 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:29.581 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:30.211 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:30.872 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:31.513 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:32.143 11862-13447/joinstore.it.testhardness V/result: ��T
01-11 17:47:32.794 11862-13447/joinstore.it.testhardness V/result: ��T
This is the data I receive from the device, I don't think there's something wrong with the implementation tha simply uses this thread after stabilizing a rfcomm connection.
//After connection, handle data transfer
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;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
// readAndPublishRaw();
readAndPublishString();
Log.v("result", "Reading data ended.");
setStatusText(-1);
}
void readAndPublishRaw(){
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
Log.v("result", "Start reading...");
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI activity
Log.v("result", bytes + "");
} catch (IOException e) {
break;
}
}
}
void readAndPublishString(){
//String method, not useful in this case?
try {
BufferedReader r = new BufferedReader(new InputStreamReader(mmInStream));
StringBuilder total = new StringBuilder();
String line;
Log.v("result", "Start reading...");
while ((line = r.readLine()) != null) {
total.append(line);
Log.v("result", line);
}
Log.v("result", total.toString());
//TODO publish read string to the view
} catch (Exception e) {
//
try {
mmSocket.close();
}catch (Exception ex){}
Log.v(TAG, "exception reading data from service");
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) {
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
setStatusText(-1);
} catch (IOException e) {
}
}
}
Can you guys give me any information about how to correctly parse this raw data? I think I should have a stream of float values, but instead I've just this random stuff.
Suggestion on how to get some usable log output first:
void readAndPublishRaw(){
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
Log.v("result", "Start reading...");
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI activity
final StringBuilder sb = new StringBuilder();
sb.append("Received ").append(bytes).append(" bytes: ");
for ( int i = 0; i < bytes; i++ ) {
sb.append( Integer.toHexString(((int)buffer[i]) & 0xff) ).append(", ");
}
Log.v("result", sb.toString());
} catch (IOException e) {
break;
}
}
}
The next step should be to calibrate the data, i.e. make note of which input/display value yields what raw data. From there, you may or may not be able to infer the actual encoding.
Your device may or may not include other information besides the actual measurement in the data, e.g. to indicate a low battery. That would have to be factored out to get raw measurement values.
If one data value comprises more than one byte the byte-order (little- or big-endian) needs to be determined.
Often floating point data of small devices is represented in a fixed point representation. Sometimes, esp. if negative numbers are needed too, with an offset added, so that
realValue = rawValue * a + c
If you find out a and c you're good. Hence, once you can relate only two different realValues and corresponding rawValues from the calibration done above, you have enough data to solve the equation for a and c.
Devices with a little more "punch", embedded linux devices for instance, may also use regular IEEE floating point data. - Not that small embedded devices cannot use IEEE, but floating point is often more than is required and comes at the price of higher complexity (memory & CPU) for the floating point emulation code.
Related
What I have :
HC-05 Bluetooth module
Arduino promini
BPM sensors
Android studio 3.0
What I have done :
Connect the Arduino, sensors, and HC-05 bluetooth using Serial
Send the data from Arduino script
Recieve and get the data using 3rd party apps from playstore
What I wanted to do :
Get the data from arduino's to be showed in the android text view, using native coded apps (not the one from the store) using android studio.
My current code :
Arduino script :
loop(){
Serial.println("*"+String(BPM)+"#"); //BPM from sensor
delay(200)
}
And some code for connecting and pairing using Android Bluetooth Adapter, which I can't showed here full because still hard coded, but the point is :
I made a handler, which recieves incoming inputs from the serial, and at least showing them on Toast component, but still haven't managed to make it work.
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE:
Toast.makeText(getApplicationContext(),"Data in",Toast.LENGTH_SHORT
).show();// if receive massage
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("\r\n"); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
sensorView0.setText("Data from Arduino: " + sbprint); // update TextView
btnOff.setEnabled(true);
btnOn.setEnabled(true);
}
//Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
break;
}
};
};
I also have a class :
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[256]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
Toast.makeText(getApplicationContext(),"Masuk ke handler private class",Toast.LENGTH_SHORT
).show();
// Read from the InputStream
bytes = mmInStream.read(buffer); // Get number of bytes and message in "buffer"
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Send to message queue Handler
} catch (IOException e) {
break;
}
}
}
}
Which I think calls for the handler to read the message, but haven't managed to make it work.
I wanted to at least show the message to the Toast, or TextView, but haven't got a clear answer this last 3 weeks.
So anyone who can help will be appreciated.
I need to implement a TCP comunication between an IoT device(custom) and an Android App.
For the Wifi device we have a Server Socket, while in Android i have an AsyncTask as a Client Socket. Both the device and the smarthone are connected to the same network.
Here is the Android Client Socket code for the initialization/socket-read and socket-write:
Variables:
static public Socket nsocket; //Network Socket
static public DataInputStream nis; //Network Input Stream
static private OutputStream nos; //Network Output Stream
AsyncTask method doInBackgroud:
#Override
protected Boolean doInBackground(Void... params) { //This runs on a different thread
boolean result = false;
try {
//Init/Create Socket
SocketInit(IP, PORT);
// Socket Manager
SocketUpdate();
} catch (IOException e) {
e.printStackTrace();
Log.i("AsyncTask", "doInBackground: IOException");
clearCmdInStack();
MainActivity.SocketDisconnectAndNetworkTaskRestart();
result = true;
} catch (Exception e) {
e.printStackTrace();
Log.i("AsyncTask", "doInBackground: Exception");
result = true;
} finally {
try {
SocketDisconnect();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Log.i("AsyncTask", "doInBackground: Finished");
}
return result;
}
Socket Initializzation:
public void SocketInit(String ip, int port) throws IOException {
InetAddress addr = InetAddress.getByName(ip);
SocketAddress sockaddr = new InetSocketAddress(addr, port);
nsocket = new Socket();
nsocket.setReuseAddress(false);
nsocket.setTcpNoDelay(true);
nsocket.setKeepAlive(true);
nsocket.setSoTimeout(0);
nsocket.connect(sockaddr, 0);
StartInputStream();
StartOutputStream();
}
Read from Socket:
private void SocketUpdate() throws IOException, ClassNotFoundException {
int read = 0;
// If connected Start read
if (socketSingleton.isSocketConnected()) {
// Print "Connected!" to UI
setPublishType(Publish.CONNECTED);
publishProgress();
if(mConnectingProgressDialog != null)
mConnectingProgressDialog.dismiss(); //End Connecting Progress Dialog Bar
//Set Communications Up
setCommunicationsUp(true);
Log.i("AsyncTask", "doInBackground: Socket created, streams assigned");
Log.i("AsyncTask", "doInBackground: Waiting for inital data...");
byte[] buffer = new byte[3];
do{
nis.readFully(buffer, 0, 3);
setPublishType(Publish.READ);
publishProgress(buffer);
}while(!isCancelled());
SocketDisconnect();
}
}
Streams init:
public void StartInputStream() throws IOException{
nis = new DataInputStream(nsocket.getInputStream());
}
public void StartOutputStream() throws IOException{
nos = nsocket.getOutputStream();
}
Read and Write methods:
public int Read(byte[] b, int off, int len) throws IOException{
return nis.read(b, off, len); //This is blocking
}
public void Write(byte b[]) throws IOException {
nos.write(b);
nos.flush();
}
public boolean sendDataToNetwork(final String cmd)
{
if (isSocketConnected())
{
Log.i("AsyncTask", "SendDataToNetwork: Writing message to socket");
new Thread(new Runnable()
{
public void run()
{
try
{
Write(cmd.getBytes());
}
catch (Exception e)
{
e.printStackTrace();
Log.i("AsyncTask", "SendDataToNetwork: Message send failed. Caught an exception");
}
}
}).start();
return true;
}
Log.i("AsyncTask", "SendDataToNetwork: Cannot send message. Socket is closed");
return false;
}
The application is very simple, the android app sends a command(via sendDataToNetwork method) to the IoT device and the latter sends back an "ACK" Command string.
The problem
The problem is that while the IoT device always receives the command, the smartphone rarely gets the ACK back. Sometimes i get something like "ACKACKACKACK". By debugging the IoT device i'm sure that it successfully sends back the ACK, so the problem lies in the InputStream read() method which doesn't retrieve the string right away.
Is there a way to empty the InputStream buffer right away, so that i get an "ACK" string back from the IoT device every time i send a command?
Update
I've updated the socket config so that there are no more buffer limitations and i've replaced read() method with readFully. It greatly improved, but still make some mistakes. For istance one out of 2-3 times no ack is received and i get 2 ack the next turn. Is this perhaps the computational limit of the IoT device? Or is there still margin for a better approach?
the problem lies in the InputStream read() method which doesn't empty the buffer right away.
I don't know what 'empty the buffer' means here, but InputStream.read() is specified to return as soon as even one byte has been transferred.
Is there a way to empty the InputStream buffer right away, so that i get an "ACK" string back from the IoT device every time i send a command?
The actual problem is that you could be reading more than one ACK at a time. And there are others.
If you're trying to read exactly three bytes, you should be using DataInputStream.readFully() with a byte array of three bytes.
This will also get rid of the need for the following array copy.
You should not mess with the socket buffer sizes except to increase them. 20 and 700 are both ridiculously small values, and will not be the actual values used, as the platform can adjust the value supplied. Your claim that this improved things isn't credible.
You should not spin-loop while available() is zero. This is literally a waste of time. Your comment says you are blocked in the following read call. You aren't, although you should be. You are spinning here. Remove this.
I am writing an embedded application for Infineon XMC4500 microprocessor.
I read data from different sensors and I send this data by means of bluetooth module in order to visualize them on the screen of Android smarphone. I use GraphView library.
I implemented BluetoothClass according to Android tutorial. If I get data from single sensor then everything is ok. But when I get data from multiple sensors unfortunately my application does not work smoothly.
Of course I am doing Bluetooth connection in seperate thread and I try to update UI in Handler.
Tell me please what am I doing wrong. Of course I send data by means of JSON exchange format:
I send something like this from the microcontroller side:
sprintf(json_data, "{"
"\"m\":"
"["
"{"
"\"id\":a,"
"\"x\":%.2f,"
"\"y\":%.2f,"
"\"z\":%.2f"
"},"
"{"
"\"id\":g,"
"\"x\":%.2f,"
"\"y\":%.2f,"
"\"z\":%.2f"
"},"
"{"
"\"id\":m,"
"\"x\":%.2f,"
"\"y\":%.2f,"
"\"z\":%.2f"
"},"
"{"
"\"id\":t,"
"\"x\":%.2f"
"},"
"{"
"\"id\":h,"
"\"x\":%.2f"
"}"
"]"
"}", getAccelXf(), getAccelYf(), getAccelZf(), getGyroXf(), getGyroYf(), getGyroZf(), getMagnetXf(), getMagnetYf(), getMagnetZf(), readTemperature(), readHumidity());
As an attachment to my request I add pieces of source code:
public class ConnectedThread extends Thread
{
BluetoothSocket connectedSocket;
InputStream inStream;
OutputStream outStream;
public ConnectedThread(BluetoothSocket socket)
{
connectedSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try
{
if (connectedSocket != null)
{
tmpIn = connectedSocket.getInputStream();
tmpOut = connectedSocket.getOutputStream();
mHandler.obtainMessage(Constants.MESSAGE_DEVICE_CONNECTED_SUCCESSFULLY).sendToTarget();
// Toast.makeText(activityContext, "connectedSocket != null", Toast.LENGTH_LONG);
}
}
catch (IOException e) {
mHandler.obtainMessage(Constants.MESSAGE_INPUT_OUTPUT_STREAM_UNAVAILABLE).sendToTarget();
e.printStackTrace();
}
inStream = tmpIn;
outStream = tmpOut;
}
public void run()
{
if(bluetoothAdapter.isDiscovering()){
bluetoothAdapter.cancelDiscovery();
}
byte[] buffer = new byte[4096];
int bytes;
String dupa;
while (true)
{
try {
if (inStream != null)
{
bytes = inStream.available();
if(bytes > 0 && bytes <= 200)
{
byte[] pocketBytes = new byte[bytes];
inStream.read(pocketBytes);
//Log.d(TAG, "setState() " + mState + " -> " + state);
System.out.println(pocketBytes.toString());
dupa = pocketBytes.toString();
System.out.println(dupa);
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, pocketBytes).sendToTarget();
}
}
} catch (IOException e) {
mHandler.obtainMessage(Constants.MESSAGE_REMOTE_DEV_DISCONNECTED).sendToTarget();
break;
}
/*try
{
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
outStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
connectedSocket.close();
} catch (IOException e) { }
}
}
}
And after that I try to update UI in the Handler.
This is link to sample of my application:
https://www.youtube.com/watch?v=_Buv64vADNk&feature=youtu.be
It does not work smoothly, morever sometimes it does not respond.
Could you please tell me what am I doing wrong ? Thx in advance.
Mateusz; Look into operational blocks force your code into the background at a lower priority that the UI code. You can also try GCD. Here a very simple block of code, spun off as a separate process.
How to determine when all images have been downloaded from a set in Swift?
Put the UI code at the highest priority and bluetooth at the lowest; making double sure the only statements you put into UI updates are doing that, don't put anything there that isn't updating the UI.
i have already get result from thread that running in same activity, but after change activity i cant get that result. is there any way to get that result ?
here my Thread, i get the result from runOnUiThread
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;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
final String s = new String(buffer);
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), s.toString(),
Toast.LENGTH_SHORT).show();
txtcomand.setText(s);
intent.putExtra("ct", s);
}
});
// Send the obtained bytes to the UI activity
// .obtainMessage(MESSAGE_READ, bytes, -1, buffer)
// .sendToTarget();
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
You could define an interface to communicate between different activitys or classes.
Just create the interface with methods that allow you to pass the data you need.
Then implement it on the receiver activity, when you create your second activity you need to pass the instance of the receiver activity and store it.
Then you can call that method and pass any parameter when you need.
Hope this helps.
I would recommend implementing a Service class instead of using a thread for your socket communication. A Service can run independently of your activities and different activities can communicate with your service in a number of ways.
For example i would implement a service and an event bus such as Otto (http://square.github.io/otto/) - its a few lines of code implementation. And then you can send your result without worrying about activities, and you activities/fragments can subscribe to those events. Its the easiest/safest way to communicate in your case, IMO, and you will have a nicely modular system.
Btw if you still want to use your thread, you can just add the event bus and use it for communication.
There are also other ways to pass that data. Interfaces for example, Broadcast receivers...
I'm facing the following problem:
I am connecting two devices via Bluetooth socket, one tablet android and a bluetooth device like reader barcode, up to now it's ok, the problem is, when a read the barcode by the bluetooth device and I send it to tablet, the bar code sometimes it's sent in two parts, for example, if I read a barcode with content "212154521212", the tablet receive "2121" and after "54521212", Anyone know tell me what should I do to avoid this?
Thanks in advanced.
My code that read the data from bluetooth device:
[code]
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private BluetoothSocket socket;
public ConnectedThread(BluetoothSocket socket) {
this.socket = socket;
InputStream tmpIn = null;
try {
tmpIn = socket.getInputStream();
} catch (IOException e) {
new LogDeErrosRodesTablet(e);
Log.e(TAG, e.getMessage());
Log.e(TAG, "Erro no construtor da classe ConnectedThread.");
}
mmInStream = tmpIn;
}
public void run() {
// continua lendo o inputstream até ocorrer um erro
while (true) {
int read = 0;
byte[] buffer = new byte[128];
do {
try {
read = mmInStream.read(buffer);
Log.e(TAG, "read: " + read);
final String data = new String(buffer, 0, read);
Log.e(TAG, "data: " + data);
//TODO
//send data only (bar code) only after read all
Bundle bundle = new Bundle();
bundle.putString(TelaInserirPedido.CODIGO_BARRAS, data);
Message message = new Message();
message.what = TelaInserirPedido.MSG_COD_BARRAS;
message.setData(bundle);
//Send a message with data
handler.sendMessage(message);
} catch(Exception ex) {
read = -1;
return;
}
Log.e(TAG, "inside while.");
} while (read > 0);
Log.e(TAG, "outside of while.");
}
}
public void cancel () {
try {
socket.close ();
} catch ( IOException e) { }
}
}
[/code]
This isn't a Bluetooth error. The Bluetooth device is sending all of the data to your application, but you are reading the stream before all of the data have been received. You could check for the amount of bytes available() on the stream before reading, if you know the exact length of the data; you could concatenate the results of all of the reads until you reach a known end point. Or you could put in an arbitrary time delay and hope the transmission completed in that time.
You would create the Bundle and Message after the while loop that collects the input string, because you don't know the entire string until that loop finishes. (Unless you are expecting multiple strings in one connection, in which case you need more complex code to handle partial numbers).
Use OutputStream.flush() to force send the all data.