I was trying to transfer sensor data to string sentence to sentence
Arduino send a sentence which is to 'btSerial.read()'
And An app received the sentence with Bluetooth handler.
when I send "<123,456>" the app received sometimes <23,456>" or "<123,456>"
when I send "<10,10>" the app received sometimes "<0,10>>>"...
I don't understand why it happens. Could someone tell me? why?
Arduino Code
include <SoftwareSerial.h>
SoftwareSerial btSerial(5,6); //RX, TX
void setup() {
Serial.begin(9600);
btSerial.begin(9600);
}
void loop() {
if(Serial.available()) {
btSerial.write(Serial.read());
}
if(btSerial.available()) {
Serial.write(btSerial.read());
}
}
And send "<123,456>" with Serial monitor
Android Studio - Received data (Handler part)
public Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == handlerState) {
String readMessage = (String) msg.obj;
recDataString.append(readMessage);
int endOflineIndex = recDataString.indexOf(">");
if (endOflineIndex > 0) {
if (flag == 1) { //Wait until flag=1,after this flag=0.
Log.d(Tag, String.valueOf(recDataString));
textview.setText("received data : " + readMessage);
}
recDataString.delete(0, recDataString.length());
flag = 0;
}
}
}
}
...
Android Studio - send sensor data part
#Override
public void onSensorChanged(SensorEvent event) {
x = ((int) event.values[0] + 10) * 13;
y = ((int) event.values[1] + 10) * 13 / 3;
if (connect) {
if ( flag ==0) {
xx = Integer.toString(x);
yy = Integer.toString(y);
connectedThread.send("<" + xx + "," + yy + ">");
flag = 1;
}
else {
}}
Android Studio - Bluetooth Thread part
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException ignored) {
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024];
int bytes; // bytes returned from read()
// keep listening to the InputStream untill an exception occurs
while (true) {
try {
// Read from the Inputstream
bytes = mmInStream.read(buffer);
final String readingMessage = new String(buffer, "US-ASCII");
mHandler.obtainMessage(handlerState, bytes, -1,readingMessage).sendToTarget();
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
...
I found the same issue while receiving data from an STM micro controller. For me, if I slow the data from the mcu down and shorten the length of data received its not as bad.
The best thing to do is to put and end of message delimiter in your arduino code then check for the delimiter in android. Something like "\n".
Related
I am trying to build a client/server model between a desktop program (C/C++, command line only for now) and an Android device, which will be used for sending data objects later.
I am a complete newbie in client/server programming. As a start, I managed to build a working connection for a simple chat, however there are some bugs which I am struggling to understand. The client can send a message only once and the server cannot respond at all.
Do you have any ideas? Maybe the buffer? Or the connection itself? I spent quite a few hours trying to understand, but I couldn't figure it out.
Below is the code(only the relevant parts):
Server:
int main (int argc, char *argv[]) {
int sockfd, newsockfd;
int pid;
int portno;
socklen_t clilen;
int n;
int portNum = 1500;
char buffer[2048];
struct sockaddr_in serv_addr, cli_addr;
struct sockaddr_in {
short sin_family; /* must be AF_INET */
u_short sin_port;Server:
struct in_addr sin_addr;
char sin_zero[8]; /* Not used, must be zero */
};
if (argc < 2) {
fprintf(stderr,"Server: ERROR, no port provided");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
error("Server: ERROR opening socket");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
serv_addr.sin_addr.s_addr = INADDR_ANY;
if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
error ("Server: Error on binding");
}
if (listen(sockfd, 1) != 0) {
perror("listen");
exit(EXIT_FAILURE);
}
clilen = sizeof(cli_addr);
while (1) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) error("ERROR on accept");
bzero(buffer, 2048);
n = read(newsockfd, buffer, 2047);
if (n < 0) error("ERROR in reading");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message", 18);
if (n < 0) error("ERROR in writing");
}
return 0;
}
Client:
public class AndroidClientActivity extends AppCompatActivity {
private static final String hostname = "127.0.0.1";
private static final int portnumber = 1500;
private static final String debugString = "debug: ";
Socket socket = null;
private EditText textField;
private Button sendButton;
private String message = "";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.android_client_activity);
textField = (EditText) findViewById(R.id.edit);
sendButton = (Button) findViewById(R.id.send_msg);
new Thread() {
#Override
public void run() {
Log.i(debugString, "Running");
//Connecting
Log.i(debugString, "Trying to connect...");
//connect
try {
socket = new Socket(hostname, portnumber);
Log.i(debugString, "Connected");
} catch (IOException e) {
e.printStackTrace();
Log.e(debugString, e.getMessage());
}
//Send message to server
sendButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
message = textField.getText().toString();
textField.setText("");
Log.i(debugString, "On click detected");
//send and get msg to server
try {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("This is a message from the client: " + message);
bw.newLine();
bw.flush();
Log.i(debugString, "Client: Message sent.");
} catch (IOException e) {
e.printStackTrace();
Log.e(debugString, e.getMessage());
}
}
});
try {
//Get message from the server
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //get the content from the socket's input stream
String msg = br.readLine();
System.out.println("Server: " + msg);
Log.i(debugString, "Client: message received from server." + msg);
} catch (IOException e) {
e.printStackTrace();
Log.e(debugString, e.getMessage());
}
}
}.start();
}
}
I've read data from sensor in android app via bluetooth using following code
try {
int byteCount = inputStream.available();
if (byteCount > 0) {
count++;
byte[] rawBytes = new byte[byteCount];
inputStream.read(rawBytes);
final String string = new String(rawBytes, "UTF-8");
handler.post(new Runnable() {
public void run() {
textView.append(string);
textView.append("\n");
}
});
}
} catch (IOException ex) {
stopThread = true;
}
This code read 10 as 1 and 0, So I want to read whole string . What will be required code for it?
I have a problem with receiving irregular sequence of the byte messages I send from another device.
The setup is the following: I have an Android app (client) and Real-Time system (server) with Ethernet both connected in a LAN through router, which talk with raw bytes communication.
From the Android app I send request, which causes the server to respond with several messages - the first one with 8 bytes, the following messages have 27 bytes. I have debugged the server and I am sure the first message it sends is the 8th-byte one, followed by the others.
About the app - I use the Main Activity to handle transmission of data through the socket, and additional thread to handle reception of data.
The thread makes post through Handler to the Main Activity, when new data has been received. In this post is called a process to parse the received data.
TbProtocolProcessor is a class I use to handle my custom protocol. It can create a byte array for me to send as request for specific function, and it has a state-machine to process expected response from the server. InetHandler is nested class I use to handle my connectivity only.
My question is - why would my Android app return me the first message having size 8, but contents like the next messages? Interesting effect is that if I send ONLY the 8-byte message, without any others, it is received and passed to my app correctly.
Here is the code:
public class MainActivity extends AppCompatActivity
{
private TbProtocolProcessor tbProtPrcs = null;
private InetHandler inetHandler = new InetHandler(this);
private static Handler msgHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tbProtPrcs = new TbProtocolProcessor(this);
}
// Implementation of InetControl interface
public void ConnectToIP(String strIP, int port)
{
inetHandler.AttachToIP(strIP, port);
}
public void Disconnect()
{
inetHandler.DetachFromIP();
}
public void GetFilesList()
{
byte[] data = TbProtocolProcessor.buildFilesGetList();
inetHandler.SendData(data, data.length);
TbProtocolProcessor.setExpectedResult(
TbProtocolProcessor.TB_STATE_WAIT_MUL_FILESLIST,
data[1],
1);
}
private class InetHandler
{
protected static final int cTARGET_PORT_UNASSIGNED = 0xFFFF;
protected String targetIP = null;
protected int targetPort = cTARGET_PORT_UNASSIGNED;
protected boolean isConnected = false;
protected Socket socket = null;
protected DataOutputStream sockStrmOut = null;
protected DataInputStream sockStrmIn = null;
protected Context context = null;
public InetHandler(Context ctx) {
if (ctx != null)
{
context = ctx;
}
}
class ClientThread implements Runnable {
byte[] indata = new byte[100];
int inCntr;
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(targetIP);
socket = new Socket(serverAddr, targetPort);
socket.setKeepAlive(true);
// DataOutputStream is used to write primitive data types to stream
sockStrmOut = new DataOutputStream(socket.getOutputStream());
sockStrmIn = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
if (socket.isConnected()) {
isConnected = true;
//Toast.makeText(context, "CONNECTED", Toast.LENGTH_SHORT).show();
//findViewById(R.id.action_connect).setBackgroundColor(0xFF60FF60);
}
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
// TODO:
while (isConnected) {
try {
inCntr = sockStrmIn.read(indata);
}
catch (IOException e) {
e.printStackTrace();
}
if (inCntr > 0) {
msgHandler.post(new Runnable() {
#Override
public void run() {
if ( tbProtPrcs.Process(indata, inCntr) ) {
Toast.makeText(context, "Operation Success", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(context, "Operation ERROR", Toast.LENGTH_SHORT).show();
}
}
});
}
}
}
}
public void AttachToIP(String sIP, int iPort)
{
if ( (isIPValid(sIP)) && (iPort < cTARGET_PORT_UNASSIGNED) )
{
targetIP = sIP;
targetPort = iPort;
// Start the connection thread
new Thread(new ClientThread()).start();
}
}
public void DetachFromIP()
{
try {
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
public boolean SendData(byte[] data, int size)
{
boolean bResult = false;
try
{
if ( (data != null) && (size > 0) && (sockStrmOut != null) ) {
Toast.makeText(context, "Sending...", Toast.LENGTH_SHORT).show();
sockStrmOut.write(data, 0, size);
bResult = true;
}
} catch (Exception e) {
e.printStackTrace();
}
return bResult;
}
public boolean isIPValid (String ip) {
try {
if (ip == null || ip.isEmpty()) {
return false;
}
String[] parts = ip.split( "\\." );
if ( parts.length != 4 ) {
return false;
}
for ( String s : parts ) {
int i = Integer.parseInt( s );
if ( (i < 0) || (i > 255) ) {
return false;
}
}
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
}
}
You're assuming that read() fills the buffer. It isn't specified to do that. See the Javadoc. If you want to fill the buffer you must use readFully().
NB isConnected() cannot possibly be false at the point you're testing it.
I have a app that connects by bluetooth with Arduino. The app is ok, but when I start an another activity my textview doesn't update.
I have a Thread that reads the data of bluetooth, and I have a timer that refreshes the textview.
If you start activity the first time and I return the main activity the textview refreshes ok, but if I start the activity again when I return the main the textview doesn't refresh.
HELP!!!
OnCreate:
bluetoothIn = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == handlerState) {
String readMessage = (String) msg.obj;
MetrosRecorridos += ((Calibracion / Imanes / 1000) * readMessage.length()) * Sentido;
}
}
};
in button that connects with bluetooth:
mConnectedThread = new ConnectedThread(mmSocket);
mConnectedThread.start();
The Thread:
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
//creation of the connect thread
public ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
//Create I/O streams for connection
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[256];
int bytes;
// Keep looping to listen for received messages
while (true) {
try {
bytes = mmInStream.read(buffer); //read bytes from input buffer
String readMessage = new String(buffer, 0, bytes);
// Send the obtained bytes to the UI Activity via handler
bluetoothIn.obtainMessage(handlerState, bytes, -1, readMessage).sendToTarget();
} catch (IOException e) {
txtConectado = "Sonda: Desconectado";
//Toast.makeText(getBaseContext(), "Fallo de conexión", Toast.LENGTH_LONG).show();
break;
}
}
}
//write method
public void write(String input) {
byte[] msgBuffer = input.getBytes(); //converts entered String into bytes
try {
mmOutStream.write(msgBuffer); //write bytes over BT connection via outstream
} catch (IOException e) {
//if you cannot write, close the application
Toast.makeText(getBaseContext(), "Connection Failure", Toast.LENGTH_LONG).show();
finish();
}
}
}
The Timer that refreshes the textview:
public void startTimer(){
t = new Timer();
task = new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
TextView t;
t=(TextView)findViewById(R.id.txtA);
t.setText(""+MetrosRecorridos);
}
});
}
};
t.scheduleAtFixedRate(task, 0, 10);
}
And the code when I call another activity:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.opc_ajustes) {
bluetoothIn.removeCallbacksAndMessages(null);
Intent i = new Intent(getApplicationContext(), AjustesActivity.class);
i.putExtra("distancia", Math.floor(MetrosRecorridos / 10));
startActivityForResult(i, 3);
return true;
}
}
Thanks!!!
I can't understand the problem clearly. But i think thread stops when activity on pause. In that case you should create a singleton timer for that purpose or use timer into application class. In activity inside the onResume method , start another thread for refreshing Textview. I hope this helps
Global Timer in android
I am working with the Bluetooth chat example and I am trying to send "dummy" data in specific intervals from a thread that's active when the Bluetooth device is connected. Is it a good idea to start/stop another service to call a method in the original service every so often? How would I implement this?
private class ConnectedThread extends Thread {
static private final String TAG = "PhoneInfoConnectedThread";
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
Log.d(TAG, "In and out streams created");
} catch (IOException e) {
Log.e(TAG, "temp sockets not created " + e.getMessage());
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
// this is where we will spend out time when connected to the accessory.
public void run() {
// Keep listening to the InputStream while connected
while (true) {
// do whatever
}
}
// Write to the connected OutStream.
public void write(byte[] buffer) {
if (mmOutStream == null) {
Log.e(TAG, "ConnectedThread.write: no OutStream");
return;
}
try {
Log.d(TAG, "ConnectedThread.write: writing " + buffer.length
+ " bytes");
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
// mHandler.obtainMessage(PhoneInfoActivity.MESSAGE_WRITE, -1,
// -1, buffer).sendToTarget();
Log.d(TAG, "ConnectedThread.write: sent to calling activity");
} catch (IOException e) {
Log.e(TAG, "Exception during write" + e.getMessage());
}
}
public void cancel() {
try {
Log.d(TAG, "ConnectedThread.cancel: closing socket");
if (mmSocket != null)
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "ConnectedThread.cancel: socket.close() failed"
+ e.getMessage());
}
}
}
May this example help you.
MyTimerTask myTask = new MyTimerTask();
Timer myTimer = new Timer();
myTimer.schedule(myTask, 2000, 1000);
class MyTimerTask extends TimerTask {
public void run() {
Log.v("TAG","Message");
}
}
for more information see this