I'm developing an app to communicate with a PCB board via bluetooth.
I receive a string from the PCB board to my app every 50ms. This string has the next structure:
start_byte(1byte)/battery _level(1byte)/speed(1byte)/mode(1byte)
So I'll receive a string like this (I'll put it in hex):
80464B11
each 50ms.
This is the code. First this is the ConnectedThread which listens for the communication and that sends the received message to the mainActivity:
public void run() {
byte[] buffer = new byte[1024];
int readed;
while (true) {
try {
readed = inputStream.read(buffer);
if (readed > 0) {
final byte[] temp = new byte [readed];
System.arraycopy(buffer, 0, temp, 0, readed);
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
/*Sends message to UI*/
connectionListener.msgRead(temp);
}
});
}
} catch (IOException e) {
...
break;
}
}
Then in MainActivity I operate with the received string to extract from it each value.
#Override
public void msgRead(byte[] buffer) {
String income = byteArrayToHex(buffer);
...
Here the next step would be to check for the start_byte and after this, get the other values.
But here comes my doubt. This string will be received each 50ms, so I'll be receiving something like this:
80464B1180464B1180464B1180464B1180464B1180464B1180464B1180464B1180464B11...
So, what I do to check for the start_byte is this:
String start_byte = income.substring(0, 2);
And then, if that matches with the start_byte value, I extract the rest of the values:
if (start_byte.equals("80")) {
...
Is my approach correct to face this? Won't the buffer overflow? How can I correctly check for the start_byte to the get the other values?
maybe it is usefull to just use the read() function. This function is blocking until one byte has been read. So you can make something like this:
int[] yourArray = new int[4];
for(int i = 0; i < 4; i++)
{
yourArray[i] = inputStream.read();
}
so now your string is devived in 4 int's stored in a array.
maybe this helps you out in some sort of way
I have faced the problem this way. I've created a Queue in the ConnectedThread. Each time I receive a byte[] I put it into the Queue.
LinkedList<Byte> dataQueue = new LinkedList<Byte>();
int i = 0;
while (i< temp.length) {
dataQueue.add(temp[i]);
i++;
}
Then, when I want to get them I do:
byte readed_byte = dataQueue.pop();
This way I get a byte from the head of the queue each time I do pop().
Related
I am doing Client server communication in java successfully but now i need to write client in Android rather the java.
client: public class ExampleClient2 {
public static void main(String[] args) throws IOException,
InterruptedException {
int port = 1114;
SocketChannel channel = SocketChannel.open();
// we open this channel in non blocking mode
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("192.168.1.88", port));
if(!channel.isConnected())
{
while (!channel.finishConnect()) {
System.out.println("still connecting");
}
}
System.out.println("connected...");
while (true) {
// see if any message has been received
ByteBuffer bufferA = ByteBuffer.allocate(60);
int count = 0;
String message = "";
while ((count = channel.read(bufferA)) > 0) {
// flip the buffer to start reading
bufferA.flip();
message += Charset.defaultCharset().decode(bufferA);
}
if (message.length() > 0) {
System.out.println("message " + message);
if(message.contains("stop"))
{
System.out.println("Has stop messages");
// break;
}
else
{
// write some data into the channel
CharBuffer buffer = CharBuffer.wrap("Hello Server stop from client2 from 88");
while (buffer.hasRemaining()) {
channel.write(Charset.defaultCharset().encode(buffer));
}
}
message = "";
}
}
}
}
this code is running successfully in java but in android it consuming lots of memory and not running reliably, due to its while (true) loop its like polling , plz let me know some solution that without polling i can read and write the data.
Thanks.
You need to compact() the buffer after calling decode() (or get(), or write(), anything that takes data out of the buffer).
Youu shouldn't allocate a new buffer every time around that while loop, and you should break out of it if read() returned -1. I don't actually see a need for the while loop at all.
The following code is taken from here
Can someone please explain in deep how this works?
What is this handler and what does it do?
How is the while condition implemented?.
How does the loop proceed?
I have very crude understanding how the code works , it would very much benefit me if you could help me out. Thank you.
{
final Handler handler = new Handler();
final byte delimiter = 10; //This is the ASCII code for a newline character
stopWorker = false;
readBufferPosition = 0;
readBuffer = new byte[1024];
workerThread = new Thread(new Runnable()
{
public void run()
{
while(!Thread.currentThread().isInterrupted() && !stopWorker)
{
try
{
int bytesAvailable = mmInputStream.available();
if(bytesAvailable > 0)
{
byte[] packetBytes = new byte[bytesAvailable];
mmInputStream.read(packetBytes);
for(int i=0;i<bytesAvailable;i++)
{
byte b = packetBytes[i];
if(b == delimiter)
{
byte[] encodedBytes = new byte[readBufferPosition];
System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
final String data = new String(encodedBytes, "US-ASCII");
readBufferPosition = 0;
handler.post(new Runnable()
{
public void run()
{
myLabel.setText(data);
}
});
}
else
{
readBuffer[readBufferPosition++] = b;
}
}
}
}
catch (IOException ex)
{
stopWorker = true;
}
}
}
});
workerThread.start();
}
void sendData() throws IOException
{
String msg = myTextbox.getText().toString();
msg += "\n";
mmOutputStream.write(msg.getBytes());
myLabel.setText("Data Sent");
}
Be sure to know what a thread is, or I can clarify it.
The code you provide, as you should know, is defining your workerThread. All that is written in the run method will be run in another thread, once you call start() on that thread. All the the variables defined before the run method are define in the main thread. So is the Handler.
A Handler aims at linking 2 threads. You define it in one thread (here the main thread before the run method), and you use it in another thread (in the run method) to execute some action in thread where it was defined. SO in your code, you call
handler.post(new Runnable()
{
public void run()
{
myLabel.setText(data);
}
});
from the workerThread, so
myLabel.setText(data);
will be executed from the main thread (the thread where was instantiated your handler).
Why is it doing so? Because .setText() can't be called from another thread than the main thread as it is drawing something.
The while loop checks that the thread hasn't been interrupted (by Android or something else) and that your boolean stopWorker hasn't been modified, so that there was no Exception thrown while reading from your inputStream
try{}catch(){} is just a way to manage exceptions.
.available() method gives you the number of bytes you can read from the inpuStream by calling the .read() method. If there are some available bytes (so if you phone received something from the connected device), then it reads it.
To read method works this way: you pas a byte array as argument, and it will get the available bytes from the input stream and put them into the byte array.
Then it processes the bytes received...
But for me it's not an efficient solution, because the thread will loop very fast, whereas .read() is a blocking method, so all the part checking that checking that there are some bytes available is useless, and even inefficient. .read() would make the thread sleep until new bytes are available, and thus releasing resources. Maybe there is another reason why the code is doing so but I don't see it.
Hope that's clear.
Problem
How to send UTF-8 data between the server and the client, if I can use on client only
inputStream.read()
?
Docs
Reads a single byte from this stream and returns it as an integer in
the range from 0 to 255. Returns -1 if the end of the stream has been
reached.
Without reader.readLine() and any another. (With reader I cant see end of stream)
Help please!
(full code:)
int c;
String str = new String();
while ((c = inputStream.read( )) != -1)
{
char ch = (char)c;
if(ch == '\n')
{
Log.v("", str);
final String data = str;
runOnUiThread(new Runnable()
{
#Override
public void run()
{
String put[] = data.split("#");
try
{
//cmd parsing
}
catch(Exception e)
{
//stop connection
}
}
});
str = "";
}else{
str += Character.toString(ch);
}
}
//Communication error
Help please
You might want to take a look at this previous post. There's a couple of good options on there. The read() method can be overloaded with different parameters, so you can read one byte, or n bytes. Check out the full documentation here. Basically, you'll have to read in the raw bytes, then convert them to ASCII characters. Also, I'm curious as to why you can't use BufferedReader or an equivalent class?
I have written a program that constantly reads from the Bluetooth via SPP and prints the contents in the stream to a edittext box. I have the following thread:
myTimer = new Timer();
myTimer.schedule(new TimerTask(){
#Override
public void run(){
TimerMethod();
}
},0,1000);
private void TimerMethod(){this.runOnUiThread(startReading);}
private Runnable startReading = new Runnable(){
public void run(){
EditText _txtArea = (EditText) findViewById(R.id._txtArea);
try{
inStream = btSocket.getInputStream();
}catch (IOException e3) {
_txtArea.append("inStream establishment Failed!");
}
Now the msg's incoming can be of any size and I want to keep reading until there isn't anything remaining to be read. I tried an implementation where i did something like this:
byte[] msgIn = new byte[15];
inStream.read(msgIn, 0, 15);
int len = msgIn.length;
for (int i=0; i<len; i++){
out = new Character ((char) msgIn[i]).toString();
_txtArea.append(out);
But that limits the read to 15 bytes and the code doesn't seem very effecient. If anyone is wondering why i have the following line out = new Character ((char) msgIn[i]).toString(); it's because the data coming in is in ASCII i am converting it to a char. Also using this method after reading all of the contents when there is nothing else to read the program hangs. Does anyone know a way i can keep reading until all of the data has been read?
I figured it out, for those who are interested it is because the stream should be closed before a read so that inputStream.read() will be able to reach -1 after all data has been sent
I have implemented a bluetooth connection using the now-classic Google Bluetooth Chat code. However, I have a question which I just cannot seem to wrap my brain around.
The reading of the input stream goes something like this:
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);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}
Now, that's fine if I was just printing out the characters I was receiving as in the original example. However, suppose I wanted to transfer an image file. I don't know the size of the file, so I cannot count the bytes received or anything like that. In my tests, I don't seem to be ever receiving a "-1" from the input stream, which appears to be the "norm" for reading from input streams. So how can I know that I have reached the end of the file that was being sent?
Thank you for your help and your time.
It seems Android bluetooth input streams never return -1.
I guess setup a simple protocol by sending file size in the first place and EOF signals at last will help.
No it does not. Android sends -1 only when the Socket is closed as far as I know. So a workaround could be to do a reconnect, but I was trying that for hours and did not get it working, since I do not understand this "special" Code here (copied from a Stackoverflow Thread) for setting up the socket:
BluetoothSocket tmp = null;
Log.d(TAG, "New Connection initialized");
Method m;
try {
m = device.getClass().getMethod("createRfcommSocket",
new Class[] { int.class });
tmp = (BluetoothSocket) m.invoke(device, 1);
} catch (Exception e) {
e.printStackTrace();
}
mmSocket = tmp;
This Socket only works, when my App is started for the first filetransfer. If I want to "Reconnect" with a completely new instantiated Object (and a new Socket created with that Code), the program freezes on the blocking method mmSocket.connect(). It seems like the Method never comes to an ending. This is driving me nuts...
Try
while ((bytes = mmInStream.read(buffer) != -1)
and see if that helps.
Try this:
public void run() {
byte[] buffer;
ArrayList<Integer> arr_byte = new ArrayList<Integer>();
while (true) {
try {
int data = mmInStream.read();
if(mmInStream.available()>0) {
arr_byte.add(data);
} else {
arr_byte.add(data);
buffer = new byte[arr_byte.size()];
for(int i = 0 ; i < arr_byte.size() ; i++) {
buffer[i] = arr_byte.get(i).byteValue();
}
Log.e("INPUT",new String(buffer));
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
arr_byte = new ArrayList<Integer>();
}
} catch (IOException e) {
break;
}
}
}