In UMTS I get a large number returned by getCid() (larger than the allowed value). Is this the UTRAN Cell Identity (UC-ID)?
UC-Id = RNC-Id + C-Id
Does someone knows that? How to get the C-Id from the UC-Id?
Thanks and Best,
Benny
The RNC id is the first 2 bytes of the 4 byte Cell Id (3GPP 25.401, section 6.1.5), if the network type is UMTS/HSxPA/HSPA+." I have access to an operator network and I checked in the system and it's true and correct.
Based on that please see my code how you can easily get RNCID + CID:Convert CID to ByteArray:
public static byte[] convertByteArray__p(int p_int){
byte[] l_byte_array = new byte[4];
int MASK_c = 0xFF;
for (short i=0; i<=3; i++){
l_byte_array[i] = (byte) ((p_int >> (8*i)) & MASK_c);
}
return l_byte_array;
}
Get the RNCID and CID:
public int getRNCID_or_CID__p(byte[] p_bytes, short p_which){
int MASK_c = 0xFF;
int l_result = 0;
if (p_which == Constants.CID_C) {
l_result = p_bytes[0] & MASK_c ;
l_result = l_result + ((p_bytes[1] & MASK_c ) << 8);
} else if (p_which == Constants.RNCID_C){
l_result = p_bytes[2] & MASK_c ;
l_result = l_result + ((p_bytes[3] & MASK_c ) << 8);
} else {
g_FileHandler.putLog__p('E', "getRNCID_or_CID__p invalid parameter");
}
return l_result;
}
Than you can easily call like this:
byte[] l_byte_array = new byte[4];
l_byte_array = convertByteArray__p(l_cid);
int l_RNC_ID = getRNCID_or_CID__p(l_byte_array,Constants.RNCID_C);
int l_real_CID = getRNCID_or_CID__p(l_byte_array,Constants.CID_C);
Constants RNCID_C(1) and CID_C(2) are only contants just for me to seperate which parameter will be passed through.
If CID is > 65536, it's not actually the cell-ID, but a linear combination of the real cell-ID and RNC-ID:
UTRAN_CELL_ID = RNCID x 65536 + CellID
To extract the cellID, use the modulo operation:
CellID = UTRAN_CELL_ID % 65536
To extract the RNCID, get the integer part:
RNCID = UTRAN_CELL_ID / 65536
try
(cell id % 65536)
it worked for me.
This is more simple than this. Cell ID is in the low register of the value getCid() returns, the RNC is the high register of this value (http://developer.android.com/reference/android/telephony/gsm/GsmCellLocation.html#getCid()).
So:
getCid() == RNC << 16 | CID
CID = getCid() & 0xffff
RNC = (getCid() >> 16) & 0xffff
Related
I have a piece of code obtain from a source which I need to understand regarding byte conversion and use from android spinner -
Edit: ---------------------------------------
So I was playing around with this binary operations and I don't know how these statements decide the output-
A. How the "and" plays role here?
B. Why do we need to convet it to int using toInt()? The output was same even without using it.
var biteData = ByteArray(2)
biteData[0] = (1 and 0xFF)
biteData[1] = (0 and 0xFF)
testByteToInt(biteData)
testByteToInt1(biteData)
testByteToInt2(biteData)
testByteToInt3(biteData)
fun testByteToInt(bytes:ByteArray){
val item_one:Byte = (bytes[0] + 0xFF and 0x01).toByte()
var one_item = item_one.toInt()
print(one_item)
}
// output: 0
fun testByteToInt1(bytes:ByteArray){
val item_one:Byte = (bytes[0] + 0x01 and 0xFF).toByte()
var one_item = item_one.toInt()
print(one_item)
}
// output: 2
fun testByteToInt2(bytes:ByteArray){
val item_one:Byte = ((bytes[0] + 0xFF) and 0x01).toByte()
var one_item = item_one.toInt()
print(one_item)
}
// output: 0
fun testByteToInt3(bytes:ByteArray){
val item_one:Byte = ((bytes[0] + 0x01) and 0xFF).toByte()
var one_item = item_one.toInt()
print(one_item)
}
// output: 2
class MyClass{
public byte[] getSpinnerVal(View view){
byte[] bytes = new byte[2];
Spinner spinner = null;
spinner = (Spinner) view.findViewById(R.id.spinner_item_one);
byte[0] = (byte) (spinner.getSelectedItemPosition() & 0xFF)
spinner = (Spinner) view.findViewById(R.id.spinner_item_two);
byte[1] = (byte) (spinner.getSelectedItemPosition() & 0xFF)
}
void setSpinnerVal(byte val_one,byte val_two,View view){
Spinner spinner = null;
spinner = (Spinner) view.findViewById(R.id.spinner_item_one);
spinner.setSelection((byte) ((val_one - 0x01) & 0xFF));
spinner = (Spinner) view.findViewById(R.id.spinner_item_two);
spinner.setSelection((byte) ((val_two - 0x01) & 0xFF));
}
}
void onCreate(){
MyClass mclass = new MyClass()
byte[] bytes = mclass.getSpinnerVal(spinner_view);
byte item_one = (byte) ((bytes[0] + 0x01) & 0xFF);
byte item_two = (byte) ((bytes[1] + 0x01) & 0xFF);
mclass.setSpinnerVal(some_byte_val_one, some_byte_val_two, spinner_view);
}
What I am confused about is this line where selected value gets increment by one
byte item_one = (byte) ((bytes[0] + 0x01) & 0xFF);
All it does is simple byte addition, A byte is 8 bits, so the upper bound with all one's would be 256(1111 1111) which is represented as 0xFF in hex, same goes for 1 in hex 0x01
byte item_two = (byte) ((bytes[1] + 0x01) & 0xFF);
//say byte[1] = 1, whose binary representation is 0000 0001
//0x01 = 0000 0001
//Now if you do (bytes[1] + 0x01)
// 0000 0001 //byte[1] value, which is position 1
// +0000 0001 // incremental value of 1
// 0000 0010 // which equals to 2
// and by doing [& 0xFF] is to limit the upper bound.
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.
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);
}
I am developing BLE in Android.
And I try to send string value to BLE device
It seem the string need to convert to byte before send to BLE device.
I found some code like the following , the code seems can convert the string value to byte.
private byte[] parseHex(String hexString) {
hexString = hexString.replaceAll("\\s", "").toUpperCase();
String filtered = new String();
for(int i = 0; i != hexString.length(); ++i) {
if (hexVal(hexString.charAt(i)) != -1)
filtered += hexString.charAt(i);
}
if (filtered.length() % 2 != 0) {
char last = filtered.charAt(filtered.length() - 1);
filtered = filtered.substring(0, filtered.length() - 1) + '0' + last;
}
return hexStringToByteArray(filtered);
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
private int hexVal(char ch) {
return Character.digit(ch, 16);
}
I call the above function before send the string to the BLE device like the following code.
byte[] value = parseHex(text);
mCharacteristic.setValue(value);
mBluetoothGatt.writeCharacteristic(mCharacteristic);
The BLE device will show the value which I have send to it. But the value is strange and I did not under stand what it mean.
The value what I send and the value show from BLE device are like the following.
Send BLE Show
1 1
2 2
9 9
10 16
11 17
20 32
30 48
40 64
70 112
90 144
99 153
100 16
I did not understand what the value mean show on BLE device...
Does someone help me ?
You are sending the hex values, which is a base 16 system, but your BLE Show values are in decimal.
Therefore sending 10 in hex is 1*16+0*1=16 in decimal. Similarly, 99 is 9*16+9*1=153 in decimal
I have a byte array -
byte[] byteArr = new byte[] { (byte)0x00 , (byte)0xF0 , (byte)0x03 };
I am just getting each one,
Integer byte1 = Integer.valueOf(byteArr[0]);
Integer byte2 = Integer.valueOf(byteArr[1]);
Integer byte3 = Integer.valueOf(byteArr[2]);
String pgnString = byte1.toString() + byte2.toString() + byte3.toString();
And my output is: 0-163
But I can see the correct output should be: 61443
Link--- http://www.binaryhexconverter.com/hex-to-decimal-converter
Thats because bytes are signed. (byte)0xF0 is actually the same as (byte)-16.
To convert as unsigned quantity you can mask the lower 8 bits:
int byte1 = byteArr[0] & 0xff;
int byte2 = byteArr[1] & 0xff;
int byte3 = byteArr[2] & 0xff;
String pgnString = String.valueOf(byte1 * 0x10000 + byte2 * 0x100 + byte3);
If you don't want to go through them one at a time, you can use ByteBuffer to convert to another base.
byte[] byteArr = new byte[] { (byte)0x00 , (byte)0x00 , (byte)0xF0 , (byte)0x03 };
int value = ByteBuffer.wrap(byteArr).getInt();
// value = 61443
Note: the byte[] must have a length of 4 (or call getInt() for each 4 byte part).