BluetoothSPPLibrary
BluetoothSPPLibrary copied to clipboard
What if data recieved contains 0d or 0a ?
The data we receive can randomly contain byte 0d or 0a. This won't be passed down the line through onDataReceived in BluetoothSPP.OnDataReceivedListener(). and the app won't receive correct data.
There should be a way to pass down all raw data to the listener.
This is the code from BluetoothService.java
line 358
int data = mmInStream.read();
if(data == 0x0A) {
} else if(data == 0x0D) {
buffer = new byte[arr_byte.size()];
for(int i = 0 ; i < arr_byte.size() ; i++) {
buffer[i] = arr_byte.get(i).byteValue();
}
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothState.MESSAGE_READ
, buffer.length, -1, buffer).sendToTarget();
arr_byte = new ArrayList<Integer>();
} else {
arr_byte.add(data);
}
+1 to this
There is the "when do I send the message back?" problem, though. I solved it (in my arduino device) by setting a delay/timeout of 200ms:
while(dataline.available()) {
while (dataline.available()){
buffer[i] = dataline.read();
if (buffer[i] == 0) {
end = 1;
continue;
}
i++;
if (i == buf_size) {
debugline.println("Buffer overflow");
return;
}
}
if (end == 1) continue;
debugline.print("+");
delay(200); // wait to see if there is more data
}
In my case I use 0x00 as EOT, but you can easily remove that, or (better) make it configurable.
Anyway: the way it's developed right now is too rigid (I spent some time trying to figure out why my message did not arrive, see issue #8 ), but it works pretty well once you know it. If I were you I would create a method (or four) to set the Service's behavior (and send a PR so that the rest of us can benefit):
- One for setting a timeout to deliver the message (default 200ms)
- One for setting the EOT character(s), defaults to 0x0D
- One for setting IGNORE characters, defaults to 0x0A
- and one for setting ESCAPE characters to allow ignoring any of the previous two (default: 0x1B) coming right after
Hope it helps!
I prefer it the way it is. The way the code is written means the OA OD must be received in that order. This is a read line. Chances of that occurring in the data are rare. I went one step further, I put a @ char at the beginning of my messages from an Arduino. I added code in the service function to discard chars until I get the @, so I know where the beginning of the message is. Using a checksum is one much more complex way to handle the above mentioned scenario. But for most situations the way it is written is OK.
in fact I use nearly identical code to how the service function is written on the Arduino, to receive messages.
By changing any numbers you send to ASCII, you eliminate the above problem. I use comma delimited (CSV) format to send all data back and forth. On a PC you can use the split() function to divide up the CSV format.
Use the atoi() and atof() functions on Arduino to receive numbers.
_code to receive number on Arduino_****
case 's': //set second from pc
serialBuffer.toCharArray(charbuff,6);
sec = atoi(charbuff);
setPcTime(); //set the new time ,only set time after recieving seconds, send all others first
Serial3.println(F("@,Recieved Seconds/Set Time,"));
break;
(note that I send a message back to the PC, to say I got it)
print() will change the numbers to ASCII for you.
_code to send time from Arduino_**
case 't': //send time to pc
Serial3.print(F("@,Sending Time,"));
Serial3.print(hour());
Serial3.print(",");
Serial3.print(minute());
Serial3.print(F(","));
Serial3.print(second());
Serial3.print(F(","));
Serial3.print(day());
Serial3.print(F(","));
Serial3.print(month());
Serial3.print(F(","));
Serial3.print(year());
Serial3.println(F(","));
break;
******how to receive data on PC in CSV format
Private Function GetData() As Boolean
Try
data = LoggerComm.ReadLine
If data <> "" Then
If SplitByCrLf Then
DataVal = Split(data, vbCrLf) 'Split up comma-delimited data to DataVal(0) through ?
GetData = True
Else
DataVal = Split(data, ",") 'Split up comma-delimited data to DataVal(0) through ?
GetData = True
End If
Else
GetData = False
End If
Catch ex As Exception
GetData = False
End Try
End Function
I guess the problem is that some times you can't choose what is sent through the line. Let's say you want to transfer an image, or sound? Any binary data will have random values in the input stream, so there should be a way to set your own conditions for data retrieval.
In fact, thinking again... what about being able to write your own onDataReceived callback? There could be a default (the one that is there now) but allow a user of the library to write their own and pass it in.
BTW, Bluetooth RFCOMM has sort of TCP features. It does error control, so no real need for checksums (AFAIK).
I modified the service function to fit my needs, no reason you can't do the same?
I think we're trying to improve the master library so that everyone can benefit from it... that's the beauty of Github! The main issue is breaking backwards compatibility... but this can be solved by setting the right defaults.
Yes guys, for my personal use I already modified the code to serve my need. But as @naevtamarkus said, maybe we can make it easier for everyone.
As of now I have modified my copy to spit out 0d0a every time and I count the package length to determine the end of the package. I do realize not everyone have package length in their data so this is quite specific to my application and I won't make a pull request out of it.
I have about the same issue. My code in the MCU sends Bytes and not Char (I can of course update that) using the HC-06. So I will probably update the library for my personal needs also. But it would be great as @naevtamarkus said to be able to write our onDataReceived callback.
What should I do to recieve data? I m not able to get it.
If possible ,when we send msg we can add a flag behind each message to solve the problem. the flag is the value of the result of each byte's ^(xor). it also called checksum. and we also should add the length info into the message to min the error.For me, this works.