I have a small question about Bluetooth communication, I've been going through a tutorial on YouTube on how to create an app that communicates with my arduino. Everything is going fine; however my only problem is that when I test for incoming data from arduino in the phone the string data seems to be tested randomly using Stringbuilder thus the test sometimes may or may not work. The data received is as follows "B1234." Lettet B indicates which data is received, the following numbers are the data itself and the dot indicates the end of stream. I'm New to android so I'm sorry if my question is not as clear as it should be
Here's the onReceive java code for BluetoothConnectionService:
byte [] buffer = new byte [1024];
int bytes;
//Keep listening to the InputStream until an exception occurs
while(true) {
try {
bytes mainstream.read(buffer);
String incomingMessage = new String (buffer, 0, bytes);
Intent incomingMessageIntent = new Intent ("incomingMessage");
incomingMessageIntent.putExtra ("theMessage", incomingMessage);
LocalBroadcastManager.getInstance (mContext).sendBroadcast(incomingMessageIntent);
}
catch (Exception e) {
break;
}
}
And here's the received java code in MainActivity:
publix final BroadcastReceiver mBroadcastReceiver5 = new BroadcastReceiver () {
public void onReceive(Context context, Intent intent) {
final String text = intent.getStringExtra ("theMessage");
messages.append(text); //Append StringBuilder
FragmentData.RXData.setText (messages);
messages.setLength(0);
}
}
Related
I am currently trying to create a water level readout as a progress bar in a simple Android app. Currently, I am using an Arduino Mega 2560 with a HC-05 to transmit the readout of the water level sensor. To simplify things, the arduino code is just counting up and down from 0 to 1000 and back, as follows.
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("Test for Water Sensor");
Serial1.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
for (int i = 0; i <= 1000; i++)
{
Serial1.println(i);
Serial.println(i);
delay(100);
}
for (int i = 1000; i >= 0; i--)
{
Serial1.println(i);
Serial.println(i);
delay(100);
}
}
On the android end, I am using this to convert to int, then change the progress bar. It also currently displays the unconverted message in a TextView.
mHandler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message msg){
if(msg.what == MESSAGE_READ){
String readMessage = null;
try {
readMessage = new String((byte[]) msg.obj, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
mReadBuffer.setText(readMessage);
try {
waterLevelValue = NumberFormat.getInstance().parse(readMessage).intValue();
waterLevel.setProgress(waterLevelValue);
} catch (ParseException e) {
e.printStackTrace();
}
}
if(msg.what == CONNECTING_STATUS){
if(msg.arg1 == 1)
mBluetoothStatus.setText("Connected to Device: " + msg.obj);
else
mBluetoothStatus.setText("Connection Failed");
}
}
};
The issue I am getting is that quite often (maybe 1-2 times a second) it is not reading the first digit. I can see on the Serial Monitor that all digits are going there, but on the android app, it will sometimes miss the first (eg: 443, 444, 45, 446, 447, etc)
What could be causing the issue here, I am very new to Bluetooth, so please help! More than happy to send more portions of code if needed.
EDIT: Adding code for reading input stream. Probably was important in the first place.
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.available();
if(bytes != 0) {
SystemClock.sleep(100); //pause and wait for rest of data. Adjust this depending on your sending speed.
bytes = mmInStream.available(); // how many bytes are ready to be read?
bytes = mmInStream.read(buffer, 0, bytes); // record how many bytes we actually read
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget(); // Send the obtained bytes to the UI activity
}
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
I have a Client-Server system where server is written in cpp and the client is written is Java (Android application).
The server reads an image from a local directory as an ifstream using read method.
The reading process is done inside a loop, where the program reads parts of the image every time. Every time a part of the image is read, it's sent over a socket to the client that collects all the piece inside a byteBuffer and when all the bytes of the image are transfered to the client, the client attempts to turn that array of bytes (after using byteBuffer.array() method) into a Bitmap.
This is where the problem begins - I've tried a few methods but it seems that I'm unable to turn this array of bytes into a Bitmap.
From what I understood, this byte array is probably a raw representation of the image, which can't be decodded using methods like BitmapFactory.decodeByteArray() since it wasn't encoded in the first place.
Ultimately, my question is - how can I proccess this array of bytes so that I'll be able to set the image as a source to an ImageView?
Note: I've already made sure that all the data is sent over the socket correctly and the pieces are collected in the right order.
Client code:
byte[] image_bytes
byte[] response_bytes;
private void receive_image ( final String protocol, final int image_size, final int buffer_size)
{
if (image_size <= 0 || buffer_size <= 0)
return;
Thread image_receiver = new Thread(new Runnable() {
#Override
public void run() {
ByteBuffer byteBuffer = ByteBuffer.allocate(image_size);
byte[] buffer = new byte[buffer_size];
int bytesReadSum = 0;
try {
while (bytesReadSum != image_size) {
activeReader.read(buffer);
String message = new String(buffer);
if (TextUtils.substring(message, 0, 5len_of_protocol_number).equals(protocol)) {
int bytesToRead = Integer.parseInt(TextUtils.substring(message,
len_of_protocol_number,
len_of_protocol_number + len_of_data_len));
byteBuffer.put(Arrays.copyOfRange(buffer,
len_of_protocol_number + len_of_data_len,
bytesToRead + len_of_protocol_number + len_of_data_len));
bytesReadSum += bytesToRead;
} else {
response_bytes = null;
break;
}
}
if (bytesReadSum == image_size) {
image_bytes = byteBuffer.array();
if (image_bytes.length > 0)
response_bytes = image_bytes;
else
response_bytes = null;
}
} catch (IOException e) {
response_bytes = null;
}
}
});
image_receiver.start();
try {
image_receiver.join();
} catch (InterruptedException e) {
response_bytes = null;
}
if (response_bytes != null)
{
final ImageView imageIV = (ImageView) findViewById(R.id.imageIV);
File image_file = new File(Environment.getExternalStorageDirectory(), "image_file_jpg");
try
{
FileOutputStream stream = new FileOutputStream(image_file);
stream.write(image_bytes);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
//Here the method returns null
final Bitmap image_bitmap = BitmapFactory.decodeFile(image_file.getAbsolutePath());
main.this.runOnUiThread(new Runnable() {
#Override
public void run() {
imageIV.setImageBitmap(image_bitmap);
imageIV.invalidate();
}
}
}
}
Whenever you exchange data between two machines of different architectures via sockets you need to know the Endianness (big-endian/little-endian) of each machine. If different, you will need to convert bytes to correct the data. Perhaps that's your issue. Here's a link with sample code: Converting Little Endian to Big Endian. You should be able to easily find more articles explaining the concept.
It turned out that something was wrong with my sending protocol.
After patching it up a bit it actually worked.
Thanks for the help.
I'm creating an app that sends and receive data with an arduino via bluetooth. Sending works fine, however when receiving data I don't get the first few characters of the string sent. I always don't get the first character, the second I sometimes get it, the third I almost always get it, etc.
So for example if the arduino sends "OK 1" I receive "K 1" or " 1" or "1", but never the complete string. An easy fix would be to add a few dummy characters, but that's a shit fix.
Here's the method which listens to incoming connections, directly copy/pasted from Android sample bluetooth code to send a simple string via bluetooth (though with a few fixes):
void beginListenForData()
{
final Handler handler = new Handler();
final byte delimiter = 10; //This is the ASCII code for a newline character
final boolean stopWorker = false;
final int readBufferPosition = 0;
final byte[]readBuffer = new byte[1024];
Thread workerThread = new Thread(new Runnable()
{
public void run()
{
while(!Thread.currentThread().isInterrupted() && !stopWorker)
{
try
{
int bytesAvailable = inStream.available();
int readBufferPosition2 = readBufferPosition;
if(bytesAvailable > 0)
{
byte[] packetBytes = new byte[bytesAvailable];
inStream.read(packetBytes);
for(int i=0;i<bytesAvailable;i++)
{
byte b = packetBytes[i];
if(b == delimiter)
{
byte[] encodedBytes = new byte[readBufferPosition2];
System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
final String data = new String(encodedBytes);
readBufferPosition2 = 0;
handler.post(new Runnable()
{
public void run()
{
result.setText(data);
}
});
}
else
{
readBuffer[readBufferPosition2++] = b;
}
}
}
}
catch (IOException ex)
{
}
}
}
});
workerThread.start();
}
Here's all my code in case you want to test it (warning: lots of dummy and outdated code):
MainActivity.java http://pastebin.com/cdjW4Y1V
XML layout file http://pastebin.com/Ruf5euPP
Click on the first button to connect to the arduino and click on the second button to send a string and to begin receiving data.
So yep, I have absolutely no idea why it doesn't work. It works fine with TerminalBT so it's not a problem with the arduino, it's a problem with my app, but why do I receive characters randomly?
one thing i noticed is that you should not use 10 for the delimiter.
I have encountered this error before if you use 10 then some times it does not get recognized properly.
you should use standard Java Function to parse the delimiter.
System.getProperty("line.separator");
//OR
System.lineSeparator();
I have managed to set up the connection between my arduino and the App with the help of Instructables blog.
The connection is set but i need the sensor output value of the ardunio to be displayed on a TextView. This is the Arduino code.
How do i program my Android studio program to read the output value of the serial monitor in the Arduino?
Okay, in the tutorial shows how send data from the app to arduino, but not how receive data from the arduino to your app for do this, you will need:
Send data from arduino by HC-06.
Receive and decode your data in the app.
show decoded data in the TextView.
a litle example for do this.
In Arduino:
can be the example of the arduino page you must only make sure that HC-06 is properly connected in Serial port.
In the app code you can use this code to receive data, only change the name of SocketBT instance, for the instance that you need.
private class TareaLeer extends Thread
{
#Override
public void run()
{
while(SocketBT.isConnected())
{
InputStream inputStream;
try {
inputStream = SocketBT.getInputStream();
byte[] buffer = new byte[256];
if (inputStream.available() > 0) {
inputStream.read(buffer);
int i = 0;
for (i = 0; i < buffer.length && buffer[i] != 0; i++) {
}
String strInput = new String(buffer, 0, i);
String Recepcion = strInput;
Log.d("Recibi",Recepcion);
//Here you can pass the value of recepcion to any globlal variable and show in TextView
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Parar();
}
}
for show it on TextView you can do this.
MyTextView.setText(Recepcion);
this is a very general explanation, for do it , you need know how android code works basically, but is a good example for start Android and Arduino Programming.
I'm new to StackOverflow lol, but I've been relying on this website for awhile. I have a question regarding a Java socket server that I created. Upon connection (client and server), my application creates a thread for that client. This is an MMORPG game server... at least trying to be. With one player, it doesn't lag that bad. With two, however, it began to show some lags...
If I was to spam left-right-left-right on one of the client, and move around normally with the other, the other would feel glitchy. I'm hoping to get some assistant since I've spent over a week and a half tangled up =) It's about time I ask for help.
The code is simple:
public static void main(String[] args) throws IOException{
serverRooms.put(roomNumber, new Room());
try {
System.out.println("Starting Server...");
serverSocket = new ServerSocket(9595, 20);
System.out.println("Server Started");
while(run){
Socket socket = serverSocket.accept(); // Check if we have a connection, otherwise wait
Player player = new Player(playerCount++, socket, roomNumber);
new Thread(player).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
That's how it is all started! On the Player object, it looks like :
public void run() {
while(playerIsConnected) {
try {
int msgid = input.readUnsignedByte();
messageHandler(this, msgid);
} catch (IOException e) {
System.err.println("Player have signed off");
playerIsConnected = false;
}
}
// If Player leaves, close socket, and end thread
try {
socket.close();
} catch (IOException e) {
System.out.println("We got an error while closing a socket on player " + pid + ".");
}
}
messageHandler happens to be a static method from a Final Static class. It is a global method that can be called by every thread (Can this be the cause of the lag??)
public final class MessageControl {
public static void messageHandler(Player player, int msgid) throws IOException{
DataInputStream input = player.getInputStream();
switch (msgid) {
case 10:
byte hspd = (byte) Math.signum(input.readByte());
byte vspd = (byte) Math.signum(input.readByte());
byte dir = input.readByte();
updatePlayerPosition(player);
byte spd = (byte) (hspd != 0 && vspd != 0 ? player.spd-1 : player.spd);
// Prepare packet and send to clients
ByteBuffer buffer = ByteBuffer.allocate(11);
buffer.put((byte) 10);
buffer.put(shortToByte_U16(player.pid));
buffer.put(shortToByte_U16(player.x));
buffer.put(shortToByte_U16(player.y));
buffer.put((byte)(hspd*spd));
buffer.put((byte)(vspd*spd));
buffer.put((byte)(dir));
sendPacketToAllClients(player, buffer, true);
// Update Player info
player.hspd = (byte) hspd;
player.vspd = (byte) vspd;
player.dir = dir;
player.lastUpdate = System.currentTimeMillis();
break;
}
private static void sendPacketToAllClients(Player player, ByteBuffer buffer, boolean includeMe){
for (Player otherPlayer : player.room.getPlayersInRoom()){
if (otherPlayer.pid != player.pid || includeMe){
sendPacketToClient(otherPlayer, buffer);
}
}
}
}
Regarding the shortToByte_U16(), I just created a simple method that conerts shorts to bytes (sending buffer packets via bytes to client). Example, I have about 5 of these conversions, which would include conversion for unsigned u16
public static byte[] shortToByte_16(int x){
short s = (short) x;
byte[] ret = new byte[2];
ret[0] = (byte)(s & 0xff);
ret[1] = (byte)((s >> 8) & 0xff);
return ret;
}
Looking at the following structure, any ideas why I be lagging?
EDIT : I think I improved it a lot by setting the setTcpNoDelay to true. The lag seems to still be there when I spam left/right on my end... the other player on my screen seems glitchy.
Socket socket = serverSocket.accept(); // Check if we have a connection, otherwise wait
socket.setTcpNoDelay(true); // This helped a lot!!!
Player player = new Player(playerCount++, socket, roomNumber);
new Thread(player).start();
From what I am seeing... my "spamming left/right" end seems to be missing the packet sent by the server.
Problem solved. =) setTcpNoDelay true did the trick. Regarding the part when I said I was missing packets, I actually didn't. The two messages merged and came in as one message. My program only read the first few bytes and ignored the rest. Had to put a byte in front to indicate the size of message. Once that was in place, I set a while loop to read through it til it can't read anymore. =) thanks everyone for helping me. My first post and it was a grand experience.