I'm developing and app that communicates via Bluetooth with another PCB. It consists of 3 seekbars that regulates the value of 3 parameters of the PCB.
The structure is this:
- Send petition string for read the first value
- Receive the first value
- Send petition string for read the second value
- Receive the second value
- Send petition string for the third value
- Receive the third value
The first thing that I want to do, but I don't know how is, when it enters on an if
, if this is true, then it must continue executing the code. But if it isn't true, then it should get out of the function and stop executing the code. But the way I've done it, it continues executing.
Then, other times it crashes because the way I implemented it to wait 1 second between each communication I know that isn't the best way, and few times instead of doing it right this way:
- Send petition string for read the first value
- Receive the first value
- Send petition string for read the second value
- Receive the second value
It does something like:
- Send petition string for read the first value
- Send petition string for read the second value
- Receive the first value
Here I receive a null string and it crashes. Now I've implemented a condition to check that is there any null string, but the solution is that I never get any null string.
When I press the "read values" button, this is what it happens:
public void receiveValues() {
/**Petition string that is sent to the PCB to request the variable's value*/
final String message_full1 = 2b e1 b4 e9 ff 1f b5; //variable 1
final String message_full2 = 2b e1 b8 e9 ff 1f b3; //variable 2
final String message_full3 = 2b e1 bc e9 ff 1f b1; //variable 3
final String message_full4 = 2b e0 bc f3 ff 1f 7c; //save request
final String message_full5 = 2b e0 be f3 ff 1f 7a; //save status
/*Send the first string to the PCB*/
byte[] send1 = message_full1.getBytes();
GlobalVar.mTransmission.write(send1);
/**Delay of 1 second to let some time to receive the confirmation*/
read1_handler.postDelayed(new Runnable() {
@Override
public void run() {
/**Read write confirmation after 1s = 1000ms*/
String inpuRead = "2b 00 ff fe c7 80"; //This string is what I receive as an answer via bluetooth
/**We check that the received string is not null, to avoid program crash*/
if (inpuRead != null) { //|| !inpuRead.equals("")) {
/*If it nos null, then we call the next function*/
int splitInt = splitReceivedString (inpuRead); //This function is declared below and extracts from the string , only the chars that we need.
receive1 = splitInt;
Toast.makeText(getApplicationContext(), "Loading values", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(getApplicationContext(), "Communication error", Toast.LENGTH_SHORT).show();
}
}
}, 1000);
/**Delay to wait to send de second petition string*/
write2_handler.postDelayed(new Runnable() {
@Override
public void run() {
/**write message 2 after 1s = 1000ms*/
byte[] send2 = message_full2.getBytes();
GlobalVar.mTransmission.write(send2);
}
}, 2000);
/**Delay of 1 second to let some time to receive the confirmation*/
read2_handler.postDelayed(new Runnable() {
@Override
public void run() {
/**Read write confirmation after 1s = 1000ms*/
String inpuRead = "2b 00 ff fe c7 80";
if (inpuRead != null) {
int splitInt = splitReceivedString (inpuRead);
receive2 = splitInt;
}
else {
Toast.makeText(getApplicationContext(), Communication error, Toast.LENGTH_SHORT).show();
}
}
}, 3000);
/**Delay to wait to send de third petition string*/
write3_handler.postDelayed(new Runnable() {
@Override
public void run() {
/**write message 3 after 1s = 1000ms*/
byte[] send3 = message_full3.getBytes();
GlobalVar.mTransmission.write(send3);
}
}, 4000);
/**Delay of 1 second to let some time to receive the confirmation*/
read3_handler.postDelayed(new Runnable() {
@Override
public void run() {
/**Read write confirmation after 1s = 1000ms*/
String inpuRead = "2b 00 ff fe c7 80";
if (inpuRead != null) {
int splitInt = splitReceivedString (inpuRead);
receive3 = splitInt;
/**Set loaded values on seekbars*/
bar1.setProgress(receive1);
bar2.setProgress(receive2);
bar3.setProgress(receive3);
/**Message indicating the end of the transmission*/
Toast.makeText(getApplicationContext(), "Values loaded!", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(getApplicationContext(), "Communication error", Toast.LENGTH_SHORT).show();
}
}
}, 5000);
/**This makes a save request on the pCB*/
write4_handler.postDelayed(new Runnable() {
@Override
public void run() {
/**write message 3 after 1s = 1000ms*/
byte[] send4 = message_full4.getBytes();
GlobalVar.mTransmission.write(send4);
}
}, 6000);
/**This request a save statos on the PCB*/
write5_handler.postDelayed(new Runnable() {
@Override
public void run() {
/**write message 3 after 1s = 1000ms*/
byte[] send5 = message_full5.getBytes();
GlobalVar.mTransmission.write(send5);
/**Reset out string buffer to zero*/
GlobalVar.mOutStringBuffer.setLength(0);
}
}, 7000);
}
/**
* FUNCTION THAT SPLITS THE RECEIVED STRING TO GET THE DESIRED VALUES
*/
private int splitReceivedString (String s) { //For example, s = 2b 00 ff fe c7 80
StringTokenizer tokens = new StringTokenizer(s," ");
String one = tokens.nextToken();
String two = tokens.nextToken();
String three = tokens.nextToken();
String four = tokens.nextToken();
String five = tokens.nextToken();
String six = tokens.nextToken();
/**The next strings are whose got the seekbar's value*/ //f.e: "fffec780"
received_hexValue = three + four + five + six;
received_hexValue = received_hexValue.trim();
/**Conversion from hex to int to set the seekbar's values*/
int_value_receive = (int)Long.parseLong(received_hexValue, 16);
int_value_receive = -200000 - int_value_receive;
newIntValue = (int_value_receive * 100) / (200000 * (-1));
return newIntValue; //For this hex value, the int value to introduce in the seekbar is "60"
}
One user on Stack Overflow has recommended me to write the code this way more clearly, and not to set a 1 second wait time because isn't the best way to do it. But I have to do something like this, because I don't have a condition to set. When i send the petition string to have the value returned, the condition would be to have this value returned, but If I don't set a time to wait between the petition sent and the returned string, mostly for sure that I'm getting a null string from the Bluetooth's input socket.
Proposed code:
private Handler handler = new Handler();
//TODO: don't call functions read1, write2 etc, call it something like "readSomeValue" where "SomeValue" is what you're trying to read
private void read1() throws IOException {
String inpuRead = "2b 00 ff fe c7 80"; //This string is what I receive as an answer via bluetooth
if (inpuRead != null) { //|| !inpuRead.equals("")) {
int splitInt = splitReceivedString (inpuRead);
receive1 = splitInt;
Toast.makeText(getApplicationContext(), "Loading values", Toast.LENGTH_LONG).show();
}
else {
throw new IOException("Error in read1");
}
}
private void write2() {
byte[] send2 = message_full2.getBytes();
GlobalVar.mTransmission.write(send2);
}
private void read2() throws IOException {
String inpuRead = "2b 00 ff fe c7 80";
if (inpuRead != null) {
int splitInt = splitReceivedString (inpuRead);
receive2 = splitInt;
}
else {
throw new IOException("Error in read2");
}
}
public void receiveValues() {
handler.post(new Runnable() {
@Override
public void run() {
try {
read1();
read2();
read3();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Communication error! " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
}