I have ntag213. I'm trying to understand how work blocks, sections of memory of my tag.
I found project https://github.com/lepunk/react-native-nfc-demo/blob/master/RNNFCDemo/App.js
but cannot understand what is agruments for transceive method:
let text = this.state.text;
let fullLength = text.length + 7;
let payloadLength = text.length + 3;
let cmd = Platform.OS === 'ios' ? NfcManager.sendMifareCommandIOS : NfcManager.transceive;
resp = await cmd([0xA2, 0x04, 0x03, fullLength, 0xD1, 0x01]); // 0x0C is the length of the entry with all the fluff (bytes + 7)
resp = await cmd([0xA2, 0x05, payloadLength, 0x54, 0x02, 0x65]); // 0x54 = T = Text block, 0x08 = length of string in bytes + 3
What it the arguments in every cmd?
You need to read Section 10 of the datasheet for the card e.g. https://www.nxp.com/docs/en/data-sheet/NTAG213_215_216.pdf
Basically with the write command (the 0xA2 first byte of the array), then you need to give it the block address, in first command this is block 4 and then block 5 (note block 4 is the first one you can write to) and then the next 4 bytes of data (as you can only write one 4 byte block at once).
So basically the commands are
[Write Command, Block Address, Data1 Byte, Data2 Byte, Data3 Byte, Data4 Byte]
So overall that code is encoding some text in a custom format to the card.
Blocks 4 and 5 are header blocks for the custom format, then it writes the text in 4 byte chucks to blocks 6 onwards all with no checking that each write was a success (other than logging the response)
Update: to answer question
for
let currentPage = 6;
let currentPayload = [0xA2, currentPage, 0x6E];
for(let i=0; i<text.length; i++){
currentPayload.push(text.charCodeAt(i));
if (currentPayload.length == 6){
resp = await cmd(currentPayload);
currentPage += 1;
currentPayload = [0xA2, currentPage];
}
}
This loop starts at the next free page after the headers (page/block 6)
A valid transceive command is 6 bytes long as detailed before.
It defines a currentPayload as partial command of 3 bytes long.
Then it iterates over the text string in a loop adding characters one at a time until the transceive command reaches 6 bytes long and then sends it. After that it increases the page number and resets the base partial command to 2 bytes long.
payload.length == 6 is how it detects a write command has all the data it can take ( 1 byte command + 1 byte address + 4 bytes data = 6 bytes in length)
This is a method of splitting a variable length text string to fit in to multiple 6 byte write commands (which have 4 bytes of data).
On further thought this possibly looks like it is trying to write a NDEF text record but I would need to check the NDEF spec in more detail to confirm it.
Related
This code is working and LED is also turning off.
byte cmd[] = {(byte) 0xff};
mWrChar.setValue(cmd);
mBleGatt.writeCharacteristic(mWrChar);
But I want to pass "0x0801000" as byte array in BluetoothGattCharacteristic, how to do this?
Similar nRF Connect application.
You can just pass an array to the variable cmd. But you need to know if the byte array is MSO (most significant octet) -> LSO (least significant octet) or LSO -> MSO. Typically, characteristics use LSO -> MSO, which means that the first octet in your byte array is the least significant octet.
In the concrete case, note that your characteristic is composed of four bytes: 0x08|01|00|00
Then you have:
MSO -> LSO: 0x08|01|00|00 -> {0x08, 0x01, 0x00, 0x00}
LSO -> MSO: 0x08|01|00|00 -> {0x00, 0x00, 0x01, 0x08}
Check out which one is relevant in your case, or try out both and see what happens. Your code will then be something like this (I assume LSO -> MSO):
byte[] cmd = {0x00, 0x00, 0x01, 0x08};
mWrChar.setValue(cmd);
mBleGatt.writeCharacteristic(mWrChar);
For sending the byte array, this is how I did it (probably from the BluetoothLeGatt sample):
characteristic.setValue((integerToSend), BluetoothGattCharacteristic.FORMAT_UINT8, 0);
characteristic.setValue((integerToSend >> 8), BluetoothGattCharacteristic.FORMAT_UINT8, 1);
The last parameter specifies the byte field in the of the characteristic. I prefer to set each field manually. With the first line I populate field 0 with the first half of my integer. With the second line I populate field 1 with the second half of my integer. You can then populate each bye field individually, up to 18 bytes per characteristic (I think)
This is the method I use to format a hex data, like yours 0x08010000, as a byte array. Then you can write it to characteristics.
public static byte[] hexToByteData(String hex)
{
byte[] convertedByteArray = new byte[hex.length()/2];
int count = 0;
for( int i = 0; i < hex.length() -1; i += 2 )
{
String output;
output = hex.substring(i, (i + 2));
int decimal = (int)(Integer.parseInt(output, 16));
convertedByteArray[count] = (byte)(decimal & 0xFF);
count ++;
}
return convertedByteArray;
}
Hope it helps.
I am newbie on Matlab, and i am trying to plot the data from the txt file written by an android application ( https://play.google.com/store/apps/details?id=com.lul.accelerometer&hl=it)
I cleaned the file and i have only the 4 columns with values separated by the " "
X Y Z time_from_previous_sample(ms)
e.g.
-1.413 6.572 6.975 0
-1.2 6.505 7.229 5
-1.047 6.341 7.26 5
-1.024 6.305 7.295 5
-1.154 6.318 7.247 5
-1.118 6.444 7.104 5
-1.049 6.225 7.173 5
-1.098 6.063 6.939 5
-0.769 6.53 6.903 5
fileID = fopen ('provamatlav.txt');
C = textscan (fileID, '%s %s %s %s');
fclose (fileID);
>> celldisp (C)`
After importing the data i created three new variables
X = C {1};
Y = C {2};
Z= C {3}
The error occur when i try to convert the cell array X into an ordinary array
xx = cell2mat('X')
the error is the following
Cell contents reference from a non-cell array object.
Error in cell2mat (line 36)
if isnumeric(c{1}) || ischar(c{1}) || islogical(c{1}) || isstruct(c{1})
Analyzing the code:
% Copyright 1984-2010 The MathWorks, Inc.
% Error out if there is no input argument
if nargin==0
error(message('MATLAB:cell2mat:NoInputs'));
end
% short circuit for simplest case
elements = numel(c);
if elements == 0
m = [];
return
end
if elements == 1
if isnumeric(c{1}) || ischar(c{1}) || islogical(c{1}) || isstruct(c{1})
m = c{1};
return
end
end
% Error out if cell array contains mixed data types
cellclass = class(c{1});
ciscellclass = cellfun('isclass',c,cellclass);
if ~all(ciscellclass(:))
error(message('MATLAB:cell2mat:MixedDataTypes'));
end
What did i do wrong?
After solved this, what would be the next step to plot the X Y Z data in the same window, but in separate graphs?
Thank you so much!
When using cell2mat, you do not need to use quotes when giving the input argument. The quotes are the reason for the error you got. Generally speaking, you would call it like so:
xx = cell2mat(X)
But you will run into a different error with this in your code, because the cell elements in your case are strings (cell2mat expects numerical values as the output). So you need to convert them to numerical format, e.g. by using this:
xx=cellfun(#str2num,X)
Please try the code line above. It worked ok in my small test case.
I am currently working on a Android application that takes values from a text box and then sends it over bluetooth, all operations are in Hex values.
I have a convertion method that can take the string make give me the unsigned integer for the string, but once i place it in the byte array it becomes signed and the board that receives this cannot do signed hex.
This is how the process works:
//sample string to send
String toSend = "0BDD";
//sending the byte[] to the board over bluetooth
btOutputStream.write(SendByteData(toSend));
// --- perform the conversion to byte[] ---
public static byte[] SendByteData(String hexString)
{
byte[] sendingThisByteArray = new byte[hexString.length()/2];
int count = 0;
for( int i = 0; i < hexString.length() - 1; i += 2 )
{
//grab the hex in pairs
String output = hexString.substring(i, (i + 2));
//convert the 2 characters in the 'output' string to the hex number
int decimal = (int)(Integer.parseInt(output, 16)) ;
//place into array for sending
sendingThisByteArray[count] = (byte)(decimal);
Log.d(TAG, "in byte array = " + sendingThisByteArray[count]);
count ++;
}
return sendingThisByteArray;
}
The issue is as follows:
When the for for loop runs through the string and picks up "0B" it correctly gives me integer 11; then when the loop runs through "DD" it give me integer 221 which is also correct
When I perform the operation of
sendingThisByteArray[count] = (byte)(decimal);
11 gets correctly placed in sendingThisByteArray[0]
but for sendingThisByteArray[1] the number 221 gets changed to -35
I know that Java has signed bytes.. is there a way to put/place/change the byte array so i can place and number 221 or any other value higher than 127?
your help is greatly appreciated
You can convert from a signed integer to unsigned byte like this, by binary AND'ing it with 0xFF:
sendingThisByteArray[count] = (byte)(decimal & 0xFF);
This way you can send values from 0 to 255
I found the problem, when i tried to do unsigned hex into a byte array it would always put a sign, i had to create single byte to retain the unsigned hex
int zeroA = (int)(Integer.parseInt("0D", 16));
sendStream.write(unsignedToBytes((byte) zeroA));
I am getting response from server in string format like
V1YYZZ0x0000010x0D0x00112050x0C152031962061900x0D410240x0E152031962061900x0F410240x1021TATADOCOMOINTERNET101
Then I am converting it in to byte array because i need to get value from this byte by byte.
I tried to use
Arrays.copyOfRange(original,
from , to);
but it work on index basis not on byte basis.
I also tried following solution but it also truncating String(if I use string instead of byte[]) on length basis.
public static String truncateWhenUTF8(String s, int maxBytes) {
int b = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
// ranges from http://en.wikipedia.org/wiki/UTF-8
int skip = 0;
int more;
if (c <= 0x007f) {
more = 1;
} else if (c <= 0x07FF) {
more = 2;
} else if (c <= 0xd7ff) {
more = 3;
} else if (c <= 0xDFFF) {
// surrogate area, consume next char as well
more = 4;
skip = 1;
} else {
more = 3;
}
if (b + more > maxBytes) {
return s.substring(0, i);
}
b += more;
i += skip;
}
return s;
}
I know how to calculate string in byte length but it giving only full string length in byte like
Here is how I need to extract packet on byte basis.
Above codes and parameters is only example. I need to get byte by byte from string/byte array.
I searched lot but didn't get any solution or link which I can refer. I am not getting how to split string using byte length because I know byte length for each parameter and for value also.
Please give me any reference or hint.
To determine what is equal to one byte in a String is not trivial. Your String contains bytes in hexadecimal text form: 0x0D (one byte, equal to 13), but also contains values as substrings. For example 1024 can be interpreted as an integer which in this case fits into 2 bytes, but could also be interpreted as a text made up by 4 chars, totaling to 8 bytes.
Anyways, I would split the string using a regular expression, and then further split the parts to length and value:
String message = "V1YYZZ0x0000010x0D0x00112050x0C152031962061900x0D41024"+
"0x0E152031962061900x0F410240x1021TATADOCOMOINTERNET101";
String regex = "(0)(x)(\\w\\w)";
String[] parts = message.split(regex);
Log.d(TAG,"HEADER = "+parts[0]);
for (int i=1; i<parts.length; i++) {
String s = parts[i];
// Only process if it has length > 0
if (s.length()>0) {
String len = "", val = "";
// String s is now in format LVVVV where L is the length, V is the value
if (s.length() < 11) {
// 1 character indicates length, up to 9 contains value
len = s.substring(0, 1);
val = s.substring(1);
} else if (s.length() > 10) {
// 2 characters indicate length, up to 99 contains value
len = s.substring(0, 2);
val = s.substring(2);
} else if (s.length() > 101) {
// 3 characters indicate length, up to 999 contains value
len = s.substring(0, 3);
val = s.substring(3);
}
Log.d(TAG, "Length: " + len + " Value: " + val);
}
}
This produces the following output:
D/Activity: HEADER = V1YYZZ
D/Activity: Length: 0 Value: 001
D/Activity: Length: 1 Value: 1205
D/Activity: Length: 15 Value: 203196206190
D/Activity: Length: 4 Value: 1024
D/Activity: Length: 15 Value: 203196206190
D/Activity: Length: 4 Value: 1024
D/Activity: Length: 21 Value: TATADOCOMOINTERNET101
Then you can check the packages (the first two package in the header is not needed), convert Strings to whatever you would like (e.g. Integer.parseInt(val))
If you explain the structure of the header (V1YYZZ0x0000010x0D0x0011205), I can improve my answer to find the message count.
I think it is doable with Scanner
import java.util.Scanner;
public class Library {
public static void main(String[] args) {
String s = "V1YYZZ0x0000010x0D0x001120"
+ "50x0C152031962061900x0D410240x0E152031962061900x0F410240x1"
+ "021TATADOCOMOINTERNET101";
// Skip first 9? bytes. I'm not sure how you define them
// so I just assumed it is 26 chars long.
s = s.substring(26, s.length());
System.out.println(s);
Scanner scanner = new Scanner(s);
// Use byte as delimiter i.e. 0xDC, 0x00
// Maybe you should use smth like 0x[\\da-fA-F]{2}
// And if you want to know that byte, you should use
// just 0x and get first 2 chars later
scanner.useDelimiter("0x\\w{2}");
// Easily extracted
int numberOfParams = scanner.nextInt();
for (int i = 0; i < numberOfParams; i++) {
String extracted = scanner.next();
// Length of message
int l = extracted.length();
boolean c = getLength(l) == getLength(l - getLength(l));
l -= getLength(l);
l = c ? l : l-1;
System.out.println("length="
+ extracted.substring(0, extracted.length()-l));
System.out.println("message="
+ extracted.substring(extracted.length()-l, extracted.length()));
}
// close the scanner
scanner.close();
}
// Counting digits assuming number is decimal
private static int getLength(int l) {
int length = (int) (Math.log10(l) + 1);
System.out.println("counted length = " + length);
return length;
}
}
We definitely need more information about rules, how string is formed. And what exactly you need to do. This code might be good enough you. And without comments it is really short and simple.
This is not a answer to accessing a byte array byte by byte, but is an answer for the situation in which you find yourself.
Your explanation and description have the appearance of being confused as to what it is that you are really getting from the server (e.g. it is quite hard to represent "V1YYZZ0x0000010x0D0x001120" as a 9 byte field (note it probably ends on the 2, not the 0)). Alternately, that you are using the wrong method to get it from the server, or not getting it as the intended data type.
Your code indicates that you believe that what you are getting is a UTF8 string. The data shown in your question does not appear to indicate that it is intended to be in that format.
Keep in mind when doing something like this that some other programmer had to create structure for the data that you are seeing. They had to define it somewhere with the intent that it be able to be decoded by their intended recipients. Unless there are other considerations (security, minimal bandwidth, etc.), such formats are usually defined in a way that is both easy to encode and decode.
The existence of the multiple "0x"-ASCII-encoded hexadecimal numbers --particularly the single byte representing the parameter (called "varam" in your graphic)-- strongly implies that this data was intended to be interpreted as a ASCII encoded string. While that might not be the case, it should be kept in mind when looking at the problem from a larger perspective.
You are having to put too much effort into decoding the information you are getting from the server. It, probably, should be relatively easy unless there are considerations why it would have intentionally been made difficult.
All of this indicates that the real problem exists in an area for which you have provided us with no information.
Step back:
Think about things like:
How are you receiving this from the server (what function/interface)?
In the call requesting the information from the server is there a way to specify the encoding type be bytes, an ASCII string, or some other format that is easier to deal with than UTF8? At a minimum, it appears to be clear that the data was not intended to be handled as a UTF8 string. There should be a way for you to get it without it having been converted to UTF8.
Also, you should try to find an actual specification for the format of the data. You have not explained much about the source, so it may be you are reverse-engineering something and have no access to specifications.
Basically, it looks like this is a problem where it might be a good idea to step back and ask if you are starting from the point that makes it easiest to solve and if you are headed in the right direction for doing so.
I'm sure I'm missing something obvious...
String.getBytes();
And if you want to process it in order taking defined objects from the array, just wrap using
ByteBuffer.wrap();
The result being something along the lines of:
String s = "OUTPUT FROM SERVER";
byte[] bytes = s.getBytes();
ByteBuffer bb = ByteBuffer.wrap(bytes);
What did I miss from the initial question? :/
I want to store an integer value and increment or decrement it with API function.
I have readed the card with an utility and this is the content of block 5:
It seems that there is not any value block.
This is my code:
int sector = 5;
this.mClassic.connect();
boolean success = this.mClassic.authenticateSectorWithKeyA(sector, MifareClassic.KEY_DEFAULT );
if(success){
int firstBlock = mClassic.sectorToBlock(sector);
Log.i("MIFARE CLASSIC", "first block of the given sector:" + firstBlock);
//set the value = 0
byte[] zeroValue = {0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0,0,};
//save this value
mClassic.writeBlock(firstBlock, zeroValue);
//increment the value and store it
this.mClassic.increment(firstBlock, 1);
this.mClassic.transfer(firstBlock);
// read the incremented value by converting it in integer from bytearray
b = readSector(firstBlock);
data = b.toByteArray();
value = 0;
for (int i = 0; i < data.length; i++)
{
value = (value << 8) + (data[i] & 0xff);
}
Log.i("MIFARE CLASSIC", "After increment " + value);
}
mClassic.close();
I have returned tranceive failed at this.mClassic.increment(firstBlock, 1);
I don't understand what I am doing wrong...who can help me?
Thanks a lot.
The Mifare 1K does a data-integrity check on the value-block. Your zeroValue block is unfortunately not a valid value-block. Therefore the tag complains and you get an error.
You can find the format in the Mifare Datasheets (worth reading!)
However, the format of the value-block is simple:
byte 0..3: 32 bit value in little endian
byte 4..7: copy of byte 0..3, with inverted bits (aka. XOR 255)
byte 8..11: copy of byte 0..3
byte 12: index of backup block (can be any value)
byte 13: copy of byte 12 with inverted bits (aka. XOR 255)
byte 14: copy of byte 12
byte 15: copy of byte 13
If you store your 32 bit value using the format above, your code will very likely just work.