akexorcist / BluetoothSPPLibrary

[UNMAINTAINED][Android] Bluetooth Serial Port Profile which comfortable to developer application to communication with microcontroller via bluetooth
Apache License 2.0
1.7k stars 572 forks source link

What if data recieved contains 0d or 0a ? #13

Open nolykhemin opened 9 years ago

nolykhemin commented 9 years ago

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);
}
naevtamarkus commented 9 years ago

+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):

Hope it helps!

rdheiliger commented 9 years ago

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


naevtamarkus commented 9 years ago

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).

rdheiliger commented 9 years ago

I modified the service function to fit my needs, no reason you can't do the same?

naevtamarkus commented 9 years ago

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.

nolykhemin commented 9 years ago

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.

BigPhiloo commented 9 years ago

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.

vidyajejurkar commented 7 years ago

What should I do to recieve data? I m not able to get it.

Lvmoy commented 7 years ago

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.