Byte array to string till '\n' - android

I have Android <-> Arduino bluetooth communication. Sometimes Android gets two messages instead of one from Arduino. What i mean: if i send for ex. 5 bytes message "1234" from Arduino to Android over bluetooth, sometimes i get "1" 1 byte in one message and "234"+\n 4 bytes in second message. Sometimes i get full "1234"+\n 5 byte message and do not have any clue why. I need to split input message by delimiter and if i get separate message i get crash. So i need to append bytes to string till new line char comes.
How to add chars to string till "\n" new line char comes?
Case when data comes:
case BLUETOOTH_RECEIVED:
byte[] buffer = (byte[])msg.obj;
int len = msg.arg1;
if (len > 0 && buffer != null) {
onBluetoothRead(buffer, len);
}
break;
}
buffer to string:
private void onBluetoothRead(byte[] buffer, int len) {
Log.i(LOGGER_TAG, String.format("Received: " + output.replace("\n", "") + " message of " + "%d bytes", len));
String output = new String(buffer, 0, len); // Add read buffer to new string
m_deviceOutput.append(output); // Add (not replace) string to TextView
StringTokenizer splitStr = new StringTokenizer(output, ","); // split string by comma
String numberOne = splitStr.nextToken(); // First split string
String numberTwo = splitStr.nextToken(); // Second split string
numberOne = numberOne.replaceAll("\\D+",""); // replace all chars, leave only numbers
numberTwo = numberTwo.replaceAll("\\D+","");
}
LogCat:
07-22 14:06:15.099: I/DeviceActivity(20370): Received: 1234 message of 5 bytes
07-22 14:06:20.599: I/DeviceActivity(20370): Received: 1234 message of 5 bytes
07-22 14:06:27.349: I/DeviceActivity(20370): Received: 1 message of 1 bytes
07-22 14:06:27.469: I/DeviceActivity(20370): Received: 234 message of 4 bytes
07-22 14:06:37.219: I/DeviceActivity(20370): Received: 1 message of 1 bytes
07-22 14:06:37.349: I/DeviceActivity(20370): Received: 234 message of 4 bytes
in Arduino i can write like this and i want something similar here:
//Get data from RS485:
void READ01(){
while (mySerial.available()){
mySerial.read();
}
mySerial.println("01READ");
momentas1="";
delay(20);
while (mySerial.available()) {
char c = mySerial.read();
if (c == '\n'){
break;
}
momentas1 += c;
}
}
This void READ01 adds chars to string until new line char comes.

You could use a buffer-like implementation by adding obtained string to another string until "\n" is received.
private String packet = "";
private void onBluetoothRead(byte[] buffer, int len) {
Log.i(LOGGER_TAG, String.format("Received: " + output.replace("\n", "") + " message of " + "%d bytes", len));
String output = new String(buffer, 0, len); // Add read buffer to new string
packet += output;
if (packet.endsWith( "\n" ) {
//do what you need to do
m_deviceOutput.append(output); // Add (not replace) string to TextView
StringTokenizer splitStr = new StringTokenizer(packet, ","); // split string by comma
String numberOne = splitStr.nextToken(); // First split string
String numberTwo = splitStr.nextToken(); // Second split string
numberOne = numberOne.replaceAll("\\D+",""); // replace all chars, leave only numbers
numberTwo = numberTwo.replaceAll("\\D+","");
packet = "";
}
}

Related

Why when reading NFCtag with Android phone you get different tag ID then when reading with dedicated reader?

I am using an Android Cilico F750 and the dedicated RFID reader is CF-RS103.
The RFID tag type is MIFARE Ultralight type C.
When read with a dedicated card reader the id of tag is: 2054270212(10 digit).
But when read with Android phone the id is: 36139312876727556(17digit) and reversed id is: 1316602805183616 (16digit).
Does anyone know why this happens and if its possible to convert the 10digit id to 17digit id or vice versa.
I use intents to detect tag and to resolve intent I use this:
public void resolveIntent(Intent intent){
String action = intent.getAction();
if(NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
||NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
||NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action))
{
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage[] msgs;
if(rawMsgs!=null)
{
msgs= new NdefMessage[rawMsgs.length];
for(int i=0; i<rawMsgs.length; i++)
{
msgs[i]=(NdefMessage) rawMsgs[i];
}
}
else
{
byte[] empty = new byte[0];
byte[] id = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);
Tag tag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
byte[] payload = dumpTagData(tag).getBytes();
NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN,empty,id,payload);
NdefMessage msg = new NdefMessage(new NdefRecord[]{record});
msgs= new NdefMessage[] {msg};
}
displayMsgs(msgs);
}}
And this are my helper functions:
private void displayMsgs(NdefMessage[] msgs)
{
if(msgs==null || msgs.length==0) {
return;
}
StringBuilder builder = new StringBuilder();
List<ParsedNdefRecord> records= NdefMessageParser.parse(msgs[0]);
final int size = records.size();
for(int i=0;i<size;i++)
{
ParsedNdefRecord record = records.get(i);
String str = record.str();
builder.append(str).append("\n");
}
text.setText(builder.toString());
}
private String dumpTagData(Tag tag) {
StringBuilder sb = new StringBuilder();
byte[] id = tag.getId();
sb.append("ID (hex): ").append(toHex(id)).append('\n');
sb.append("ID (reversed hex):").append(toReversedHex(id)).append('\n');
sb.append("ID (dec): ").append(toDec(id)).append('\n');
sb.append("ID (reversed dec):").append(toReversedDec(id)).append('\n');
String prefix = "android.nfc.tech.";
sb.append("Technologies: ");
for (String tech: tag.getTechList()) {
sb.append(tech.substring(prefix.length()));
sb.append(", ");
}
sb.delete(sb.length() - 2, sb.length());
for (String tech: tag.getTechList()) {
if (tech.equals(MifareClassic.class.getName())) {
sb.append('\n');
String type = "Unknown";
try {
MifareClassic mifareTag = MifareClassic.get(tag);
switch (mifareTag.getType()) {
case MifareClassic.TYPE_CLASSIC:
type = "Classic";
break;
case MifareClassic.TYPE_PLUS:
type = "Plus";
break;
case MifareClassic.TYPE_PRO:
type = "Pro";
break;
}
sb.append("Mifare Classic type: ");
sb.append(type);
sb.append('\n');
sb.append("Mifare size: ");
sb.append(mifareTag.getSize() + " bytes");
sb.append('\n');
sb.append("Mifare sectors: ");
sb.append(mifareTag.getSectorCount());
sb.append('\n');
sb.append("Mifare blocks: ");
sb.append(mifareTag.getBlockCount());
} catch (Exception e) {
sb.append("Mifare classic error: " + e.getMessage());
}
}
if (tech.equals(MifareUltralight.class.getName())) {
sb.append('\n');
MifareUltralight mifareUlTag = MifareUltralight.get(tag);
String type = "Unknown";
switch (mifareUlTag.getType()) {
case MifareUltralight.TYPE_ULTRALIGHT:
type = "Ultralight";
break;
case MifareUltralight.TYPE_ULTRALIGHT_C:
type = "Ultralight C";
break;
}
sb.append("Mifare Ultralight type: ");
sb.append(type);
}
}
return sb.toString();
}
private String toHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = bytes.length - 1; i >= 0; --i) {
int b = bytes[i] & 0xff;
if (b < 0x10)
sb.append('0');
sb.append(Integer.toHexString(b));
if (i > 0) {
sb.append(" ");
}
}
return sb.toString();
}
private String toReversedHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; ++i) {
if (i > 0) {
sb.append(" ");
}
int b = bytes[i] & 0xff;
if (b < 0x10)
sb.append('0');
sb.append(Integer.toHexString(b));
}
return sb.toString();
}
private long toDec(byte[] bytes) {
long result = 0;
long factor = 1;
for (int i = 0; i < bytes.length; ++i) {
long value = bytes[i] & 0xffl;
result += value * factor;
factor *= 256l;
}
return result;
}
private long toReversedDec(byte[] bytes) {
long result = 0;
long factor = 1;
for (int i = bytes.length - 1; i >= 0; --i) {
long value = bytes[i] & 0xffl;
result += value * factor;
factor *= 256l;
}
return result;
}`
EDIT: I managed to resolve this issue by truncating the 7-byte HEX ID to 4-bytes.
And then formating the decimal ID if its total lenght is less than 10 digits with this statement that basically adds zeroes from left side if DEC ID is smaller than 10 digits:
String strFinal=String.format("%010d", Long.parseLong(str));
This document that describes how the ID is converted from HEX8 TO DEC10 helped me alot aswell: https://www.batag.com/download/rfidreader/LF/RAD-A200-R00-125kHz.8H10D.EM.V1.1.pdf
And a huge thanks to #Andrew and #Karam for helping me resolve this!
The card reader on the PC is configured wrong, it is configured by default to display the ID as 10 digit decimal number (4 byte) when the card has a 7 byte ID.
It thus has to loose some data, it is doing this by truncating the ID to the first 4 bytes of the 7 byte ID
Use the software on the PC change the output format to something suitable for the ID size on the Mifare Ultralight C cards (8 Hex?)
or
Use Mifare Classic cards instead as these had 4 byte ID
or
truncate the 7 byte ID to 4 bytes e.g. change bytes.length to 4 (a hard coding to the first 4 bytes in the 7 byte ID) in your code and handle the fact that there is a very large number (around 16.7 million) of Mifare Ultralight C cards that will seem to have the same "ID" as you want to display it
This is because the spec's give by a seller on Amazon https://www.amazon.co.uk/Chafon-CF-RS103-Multiple-Support-Compatible-Black/dp/B017VXVZ66 (I cannot find any details on the manufacturer's site)
It says "Default output 10 digit Dec, control output format through software. "
"Support with windows,linux and android system, but can only set output format in windows pcs.No programming and software required, just plug and play. "
The only sensible answer is move everything to use a 7 byte ID.
I don't know why are you trying always to convert to decimal?
and please try to explain more about the code you use to read the UID.
about your numbers and to convert 17 digits to 10 digits; I convert both of them to Hex:
36139312876727556(17digit) in Hex : 8064837A71AD04.
2054270212(10 digit) in Hex: 7A71AD04
as you notice you can just tirm first three bytes to get the 10 digits.
and I do belive the both of them are not the UID. but the 7bytes as sayed Andrew, and you already read it in the your photo : (04:B5:71:7A:83:64:80)
So I think the answer is that because you are converting a 7 byte ID to decimal you are getting variable lengths of numbers because of the conversion to decimal.
"The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive)."
From https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
Could generate a decimal number with 1,2 or 3 characters thus as decimal the id can vary in length.
It also looks like that conversion is going wrong as in theory it should have negative numbers in there as well.
It is much better to handle it as a hex string if you want it to be human readable.
The correct method in Java to convert the 2 pages of the ID to hex is
StringBuilder Uid;
for (int i = 0; i < result.length; i++) {
// byte 4 is a check byte
if (i == 3) continue;
Uid.append(String.format("%02X ", result[i]));
}
Note as per the spec sheet of the card https://www.nxp.com/docs/en/data-sheet/MF0ICU2_SDS.pdf (Section 7.3.1)
There is check byte that is part of the ID, while this will always be the same on the same card and will still give you a unique ID it is technically not part of the ID.
Or if not reading at a low level then
https://developer.android.com/reference/android/nfc/Tag#getId()
will get you the id.
Note that the "36139312876727556(17digit) and reversed id" when converted to hex and reversed actual is 7 bytes and start with the right number.
The 10 digit just looks like the first 4 bytes of the 7 byte number also reversed.

Arduino send long string to Android

I'm trying to send long String to Android via bluetooth.
but,
It looks like the picture.
some characters are changed.
how can I get an exact full string?
arduino code :
for(int i=0;i<16;i++){
String rec = String(P[i], HEX);
if(rec.length()<2) rec = "0"+rec;
BTSerial.println(rec);
delay(50);
P is a byte array. Thanks.
Try it without String objects:
// return '0' .. 'F'
char hexnibble(byte nibble) {
nibble &= 0x0F; // just to be sure
if (nibble > 9) return 'A' + nibble - 10;
else return '0' + nibble;
}
void loop() {
byte P[16];
// ... fill P somehow ...
char rec[33];
for(int i=0;i<16;i++){
rec[2*i] = hexnibble(P[i] >> 4);
rec[2*i+1] = hexnibble(P[i] & 0x0F);
}
rec[32] = 0; // string terminator
Serial.println(rec); // just for debugging
delay(1000);
}

Convert byte to character string

I am trying to convert a byte to a string. The byte(s) are revieved from a bluetooth packet and separated into an array. The data is good but it show the integer value of the received data but I need to show a charature. IE value shows a 65 but I need "A" character for a textview.
The first 10 bytes in the encodedBytes sent to bluetooth {ABCDEFGHI} and the logcat shows 6566676869707172730
byte[] encodedBytes = new byte[160];
System.arraycopy(readBuf, 0, encodedBytes, 0, encodedBytes.length);
Log.d("TAG", "Tiles data ");
strArrayTitle[0]=""; // clear
for (int i = 0; i < 10; i++) { // get first 10 chars
Byte piece = (encodedBytes[i]);
strArrayTitle[0] = strArrayTitle[0] +(piece);
}
Log.d("TAG", "String Data " + strArrayTitle[0]);
}
I made some changes as per answer and made some progress. I changed the new byte to 10 and converted to string. Can I parse the data so I can convert all 160 bytes at one time ?
byte[] encodedBytes = new byte[10];
System.arraycopy(readBuf, 0, encodedBytes, 0, encodedBytes.length);
String title = new String(encodedBytes);
Log.d("TAG", "Tiles data " + title);
Try making a string like this
String title = new String(strArrayTitle);
Where strArrayTitle is a byte[];
Here is my solution to the problem. I divided the readbuf into sections and then converted to strings.
String[] Titled = new String[16];
byte[] encodedBytes = new byte[10];
for (int f=0;f < 5;f++) {
System.arraycopy(readBuf, (f * 10), encodedBytes, 0, 10);
Titled[f] = new String(encodedBytes);
Log.d("TAG", "F1 " + f);
}
Log.d("TAG", "Tiles data 1 " + Titled[0]);
Log.d("TAG", "Tiles data 2 " + Titled[1]);
Log.d("TAG", "Tiles data 3 " + Titled[3]);
Log.d("TAG", "Tiles data 4 " + Titled[4]);
}

HMAC SHA1 android with input string and input key is Hex String

this is my first post! So if anything is wrong please tell me, i am new to android developing! Here is my question:
I am trying to generate HMAC-SHA1 with input is Hexstring for example the input key is "2cb1b780138bc273459232edda0e4b96" and input value is HexString too but way longer than the key, all the value and the key are Hexstring not character or normal string, so how can i achieve this? I searched a lot but all the result came to use the value and the key in normal string like "The quick brown fox jumps over the lazy dog"
I tried using convertHextoString code to change my HexString into Character string and put in the function like you did but the converted String from convertHextoString appear to have many SPECIAL CHARACTERS such as "\n" or ":" or "%" and so on and i think that is the problem why i got the wrong output. Here is my convertHextoString function
public String convertHexToString(String hex){
StringBuilder sb = new StringBuilder();
StringBuilder temp = new StringBuilder();
//49204c6f7665204a617661 split into two characters 49, 20, 4c...
for( int i=0; i<hex.length()-1; i+=2 ){
//grab the hex in pairs
String output = hex.substring(i, (i + 2));
//convert hex to decimal
int decimal = Integer.parseInt(output, 16);
//convert the decimal to character
sb.append((char)decimal);
temp.append(decimal);
}
System.out.println("Decimal : " + temp.toString());
return sb.toString();
}
and the function to HMAC:
static String hash_hmac(String type, String value, String key) {
try { Log.i("Hien - value - hmac",value);
javax.crypto.Mac mac = javax.crypto.Mac.getInstance(type);
javax.crypto.spec.SecretKeySpec secret = new javax.crypto.spec.SecretKeySpec(key.getBytes(), type);
mac.init(secret);
byte[] digest = mac.doFinal(value.getBytes());
StringBuilder sb = new StringBuilder(digest.length*2);
String s;
for (byte b : digest){
s = Integer.toHexString(b & 0xff);
if(s.length() == 1) sb.append('0');
sb.append(s);
}
return sb.toString();} catch (Exception e) { android.util.Log.v("TAG","Exception ["+e.getMessage()+"]", e); } return ""; }
Please help!

Send and receive string values via bluetooth android

I'm developing an app where I need to send 3 seekbar's values to a PCB via bluetooth. I've done all the bluetooth code based on the bluetoothchat example. I first modified it to send a string with these 3 values. But now, I need to do something more dificult and i don't know how to do it.
First of all, in the app i modify the seekbars and then i click on the send button. In the code, I need to set a string for each seekbar's value, because I need to access to the MCU variables and set each variable address, value, CRC etc...
So, I need to know the correct way to do this. Here is the code where i define the send function:
/**
* SEND THREAD
*/
/**[Start Thread + Send command + Nº bytes thread + Nº bytes variable + Address + Variable value + CRC]*/
public void sendValues() {
/**Set the seekbars values into a string*/
send_value1 = Integer.toString(savedProgress1);
send_value2 = Integer.toString(savedProgress2);
send_value3 = Integer.toString(savedProgress3);
String message1 = start_thread+" "+send_command+" "+num_byte_trama1+ " "+num_byte_variable+" "+pos_reg_1+" "+Value+" "+CRC;
String message2 = start_thread+" "+send_command+" "+num_byte_trama1+ " "+num_byte_variable+" "+pos_reg_2+" "+Value+" "+CRC;
String message3 = start_thread+" "+send_command+" "+num_byte_trama1+ " "+num_byte_variable+" "+pos_reg_3+" "+Value+" "+CRC;
String message4 = start_thread+" "+send_command+" "+num_byte_trama2+ " "+num_byte_variable+" "+pos_reg_save_request+" "+Value+" "+CRC;
String message5 = start_thread+" "+send_command+" "+num_byte_trama2+ " "+num_byte_variable+" "+pos_reg_save_status+" "+Value+" "+CRC;
/**Check that we're actually connected before trying anything*/
if (GlobalVar.mTransmission.getState() != GlobalVar.STATE_CONNECTED) {
Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();
return;
}
/**Get the message bytes and tell the Transmission to write*/
byte[] send = message.getBytes();
GlobalVar.mTransmission.write(send);
/**Reset out string buffer to zero*/
GlobalVar.mOutStringBuffer.setLength(0);
}
There are these few things that I ask you to help me:
1- Need to know how to calculate the CRC
2- I need to send these 5 strings together when pressing the send button.
In the part where i get the bytes to send, I don't know If the right way to do this would be to add these 5 strings on 1 and send this one (maybe it would be to long if I do this), or to create a function to send these 5 separately but at the same time.
This is the edited code to send each message one by one:
/**Conversion to decimal of the seekbar's % value*/
send_int1 = ((savedProgress1 * 20480) / 100) * -1;
send_int2 = ((savedProgress2 * 20480) / 100) * -1;
send_int3 = ((savedProgress3 * 20480) / 100) * -1;
/**Conversion to string of the previous values to send in the string message*/
sendValue1 = Integer.toString(send_int1);
sendValue2 = Integer.toString(send_int1);
sendValue3 = Integer.toString(send_int1);
String message1 = start_thread+" "+send_command+" "+num_byte_trama1+" "+num_byte_variable+" "+pos_reg_1+" "+sendValue1+" " ;
String message2 = start_thread+" "+send_command+" "+num_byte_trama1+" "+num_byte_variable+" "+pos_reg_2+" "+sendValue2+" " ;
String message3 = start_thread+" "+send_command+" "+num_byte_trama1+" "+num_byte_variable+" "+pos_reg_3+" "+sendValue3+" " ;
String message4 = start_thread+" "+send_command+" "+num_byte_trama2+" "+num_byte_variable+" "+pos_reg_save_request+" " ;
String message5 = start_thread+" "+send_command+" "+num_byte_trama2+" "+num_byte_variable+" "+pos_reg_save_status+" " ;
/**Check that we're actually connected before trying anything*/
if (GlobalVar.mTransmission.getState() != GlobalVar.STATE_CONNECTED) {
Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();
return;
}
/**Get the message bytes and tell the Transmission to write*/
byte[] send1 = message1.getBytes();
GlobalVar.mTransmission.write(send1);
//Wait untill I receive the confirmation from the MCU
byte[] send2 = message2.getBytes();
GlobalVar.mTransmission.write(send2);
byte[] send3 = message3.getBytes();
GlobalVar.mTransmission.write(send3);
byte[] send4 = message4.getBytes();
GlobalVar.mTransmission.write(send4);
byte[] send5 = message5.getBytes();
GlobalVar.mTransmission.write(send5);
/**Reset out string buffer to zero*/
GlobalVar.mOutStringBuffer.setLength(0);
}
For your frame, I recommand you to use this kind of frame :
final byte[] HEADER = AA11 // For example
// When you want to send a message :
Strign messageToSend = new String(HEADER) + yourStringMessage
It'll be easier for you to analyze the frame when you receive it.
Then, for the CRC, I can't answer if you don't tell the kind of CRC. In my app, I used
private static char createCRC(byte[] frame)
{
int crc = 0;
for(byte i : frame)
{
crc = crc^i;
}
return (char)crc;
}
to create the CRC by "XORing" each byte of my message , and then check a CRC is quite easy
UPDATE : Well, I finally get it.
In the BluetoothChat activity, you get a string version of message, and the byte[] one.
If you want to get the first byte of the message, just add byte myByte = readBuf[0] before String readMessage = new String(readBuf, 0, msg.arg1);
Then, String readMessage = new String(myByte, 0, msg.arg1);

Categories

Resources