Android NfcA Transceive fails on success - android

I made a simple test application for quick debugging. I send some bytes, print what I sent on the phones screen and print what I receive.
When I send WRONG commands I get the corresponding error codes in the two byte SW1SW2.
I can also call my own command and override SW1SW2 with my own values and I can get them.
Here's the problem: When I send a CORRECT command the transceive command fails with the informative exception "Transceive failed".
If I send the correct command, but override SW1SW2 to something other than 90 00 then I get the SW value I set, but NO response data. (likely because the card does not send ODATA when SW1SW2 <> 90 00)
So how come I'm so sure I sent correct commands? Well other than messing with my own test command I called the GetAppId command - which failed saying I have to define AppId in the card.
So I define it in the card, send the same command and transceive fails.
So I'm pretty sure the problem is that transceiving fails when there is ODATA, but I do not understand WHY or how to FIX it.. help please!
EDIT: My card is the 7.5 D contactless basiccard from ZeitControl.
EDIT2: I have set the timeout to 2000ms with no change in behavior. I'm trying to return a single byte of data and the system command I called also doesn't sound heavy.
Then I downloaded and attached the Android source and debugged. There was some segments it would still not go into - but the card seems to return null on valid commands unless I return some manually set SW1SW2 in which case that is the only thing received.
EDIT3: The system command I tried was:
192 14 0 0 0
(or C0 0E 00 00 00)
(or CLA INS P1 P2 Lc)
I'm not 100% sure I'm doing that one correctly, but I have tried with various lengths (up to 22) of Le and without Le as above and only without does it not give me 6700 (wrong Le/Lc)
Of course instead of 6700 it returns null it seems...
The other command is my own defined as 20 0A (value as Byte) and no P1/P2 specified in the .BAS file.
I call that one with:
32 10 1 0 1
(or 20 0A 01 00 01)
(or CLA INS Lc IDATA Le)
This should mean 1 byte data in, set to 0, and 1 byte expected out (+ SW1/SW2 as always).
(Setting P1/P2 gives 6700 so unless defined in the command declaration I dont think they should be there)
This also returns null. I Expect 00 90 00 to be returned here. (if I set "value" to 00 that is)
I'm using a HTC One X.
EDIT4:
MinSdk version = 14 and target 18.
if(bitcoinCard != null){
try {
String sentmsg, receivedmsg;
byte[] send = getBytes(commandBytes.getText().toString());
byte[] data = null;
if(send != null){
bitcoinCard.setTimeout(2000);
data = bitcoinCard.transceive(send);
}
//bitcoinCard.close();
/*if(data != null && data.length == 2)
{
mainLabel.setText("SW1SW2: " + (data[0] < 0 ? -data[0] +
128 : data[0]) + " " + (data[1] < 0 ? -data[1] + 128 : data[1]));
}else */if (data != null && send != null)
{
sentmsg = "" + (send[0] < 0 ? send[0] + 256 : send[0]);
for(int i = 1; i < send.length; i++)
{
sentmsg = sentmsg + " " + (send[i] < 0 ? send[i] +
256 : send[i]);
}
receivedmsg = "" + (data[0] < 0 ? data[0] + 256 : data[0]);
for(int i = 1; i < data.length; i++)
{
receivedmsg = receivedmsg + " " + (data[i] < 0 ? data[i] + 256 : data[i]);
}
mainLabel.setText("Sent: " + sentmsg + "\n" +
"Response: " +
receivedmsg);
}else
{
mainLabel.setText("Sent or received null.");
}
} catch (IOException e) {
mainLabel.setText("Tried to talk to card, but had error: " +
e.getMessage());
}
}

First, when you send APDUs you should use an IsoDep object (and not NfcA). Android should show both tag technologies as available for your card. The problem here is that Android will typically only activate the card in ISO 14443-4 protocol mode if you use IsoDep. Thus, wehn using NfcA, your card will not be ready to accept APDUs.
I just tested and this is at least the case on a Nexus S with Android 4.1.2. In fact trying to transceive using the NfcA object leads to TagLostExceptions with some cards and to some other really odd behavior with another card I tried.
Second, if you send
byte[] cmd = { (byte)0xC0, (byte)0x0E, (byte)0x00, (byte)0x00, (byte)0x00 };
I would expect the card to return the actual application ID. However, the answer to this command (i.e. <data> <SW1=61> <SW2=len>) does not comply to ISO 7816-4 (no data should be returned for a 61xx status code) so this might cause a problem.
UPDATE: I just tested this with a Nexus S (Android 4.1.2) and receiving such responses was not a problem.
Last, your other command (20 0A) is not what you expect it to be:
I strongly suggest you only use CLA bytes set to 0x00 or 0x80 unless you know what you are doing (use of secure messaging, use of logical channels, ...). Though, Android (at least with NXP's NFC chipset) does not care about the structure of the APDU, but your card might!
An APDU always has the form <CLA> <INS> <P1> <P2> [Lc [DATA]] <Le> (with the special case of <CLA> <INS> <P1> <P2>). So this means you cannot simply omit P1 and P2.
You are correct in that BasicCard will discard ODATA if SW<>9000 and SW1<>61.

Related

Generate QRCode and Print in Printer Thermal using ESC POS - ZIJIANG 58mm - Delphi 10.2

I'm trying to print qr code, on a thermal pos bluetooth printer in delphi, android platform (firemonkey).
the printer is connected, I can print the text, but I can't generate and print the qr code, I would be grateful if someone can help.
The mark of the pos printer is P08-580LD (ZIJIANG).
this is the code i use in delphi-android 10.2 .
sock.connect;
// Reset Printer
ostream.write(StringToJA(escResetPrinter,'iso8859-2'));
ostream.write(StringToJA(pO8escBoldOn,'iso8859-2'));
ostream.write(StringToJA('Naziv 1'+escNewLine , 'iso8859-2'));
ostream.write(StringToJA(pO8escBoldOff,'iso8859-2'));
ostream.write(StringToJA(pO8escFontA,'iso8859-2'));
ostream.write(StringToJA('Adresa'+escNewLine , 'iso8859-2'));
ostream.write(StringToJA(escResetPrinter,'iso8859-2'));
ostream.write(StringToJA(pO8escFontB,'iso8859-2'));
ostream.write(StringToJA('MB xxxxx, ID HR-AB-99-0125--54'+escNewLine , 'iso8859-2'));
ostream.write(StringToJA(escResetPrinter,'iso8859-2'));
ostream.write(StringToJA(pO8escUnerlineOn,'iso8859-2'));
ostream.write(StringToJA('IBAN: xxxxxxxxx'+escNewLine , 'iso8859-2'));
ostream.write(StringToJA(pO8escUnerlineOff,'iso8859-2'));
ostream.write(StringToJA('OIB 99999999'+escNewLine , 'iso8859-2'));
// start - qr-code //
ostream.write(StringToJA(chr(27)+chr(90)+chr(0)+chr(7)+chr(15)+chr(25)+chr(30)+'dada' ,'iso8859-2'));
ostream.write(StringToJA(escResetPrinter,'iso8859-2'));
Sleep(250);
ostream.flush();
ostream.close;
This is documentation from the printer, and it says how to build the code, (decimal).
https://mega.nz/file/fu4zTCSR#UZ53LSty7dUpRyqzvz8li27amG1KvVlLk0slQFhd5Os
I managed to generate the qr code as below in the picture but it is not ok.
This is how the qr code should be generated according to the printer documentation
I found a function in android studio, how to build qr code, I would be grateful if someone knows how to turn a function into delphi.
.....
byte[] qrcode = PrinterCommand.getBarCommand("Zijiang Electronic Thermal Receipt Printer!", 0, 3, 6);//
Command.ESC_Align[2] = 0x01;
SendDataByte(Command.ESC_Align);
SendDataByte(qrcode);
public static byte[] getBarCommand(String str, int nVersion, int nErrorCorrectionLevel, int nMagnification)
{
if(nVersion<0 | nVersion >19 | nErrorCorrectionLevel<0 | nErrorCorrectionLevel > 3
| nMagnification < 1 | nMagnification > 8){
return null;
}
byte[] bCodeData = null;
try
{
bCodeData = str.getBytes("GBK");
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
return null;
}
byte[] command = new byte[bCodeData.length + 7];
command[0] = 27;
command[1] = 90;
command[2] = ((byte)nVersion);
command[3] = ((byte)nErrorCorrectionLevel);
command[4] = ((byte)nMagnification);
command[5] = (byte)(bCodeData.length & 0xff);
command[6] = (byte)((bCodeData.length & 0xff00) >> 8);
System.arraycopy(bCodeData, 0, command, 7, bCodeData.length);
return command;
}
Having quite similar issues on that kind of mini POS printers. When directly printing from Kotlin (Android Studio, native), I managed, somehow, to interpret partially their official manual and concluded that ESC Z works little different (actually it coresponds to the Java code you found)...
ESC Z (27 90)
first byte relates to table row ("version"), if 0 then it will "autoselect"
at first, I thougth second byte must be 'M' (77) - 'L', 'Q', 'H' - didn't manage it to work?! (actually it has to be 0,1,2,3 based on error correction - as suggested in Java code you found and posted here)
this byte relates to QR code size, 1-8
lower byte of string size (for example, for your "dada" it would be 4)
higher byte of string size (for your "dada" it would be 0... if longer than 256 characters, this shall be length div 256)
string characters
In your Delphi code, I would change (step-by-step, you can binary mask the length...):
// start - qr-code //
ps := 'dada'; // your content string... detalji o računu ili štogod...
l1 := length(ps);
y := l1 div 256;
x := l1 - y * 256;
ostream.write(StringToJA(chr(27)+chr(90)+chr(7)+chr(1)+chr(6)+chr(x)+chr(y)+ps ,'iso8859-2'));
// please not that 7-1-6 is fixed combination - 7 relates to the table from documentation, 1 relates to error correction (use 0 for "smaller" QR with less redundany, or 2 and 3 for larger more complex QR), 6 relates to size of printed code (can be set lower)

Sending a simple USB BulkTransfer and receiving a response

I am trying to get a weight value from a set of weighing scales over USB. It should be quite simple, according to their doc, I need to send two bytes the letter "W" and the carriage return byte. It then responds with 16 bytes of data representing the current weight on the device.
The device has 1 interface, 2 endpoints with a max packet size of 64. I believe I must use the bulkTransfer function as the endpoint types are USB_ENDPOINT_XFER_BULK.
Here is the doc graphic:
How exactly should I send this request and receive the response? My attempt is below, and the response is simply a Start of Heading symbol, then a back quote symbol "`" and a load of zeroes. I have tried to run the code on a polling loop or just a single request but get the same result.
val connection = usbManager.openDevice(scales)
val intf: UsbInterface = scales.getInterface(0)
connection.claimInterface(intf, true)
val endpointReadIn = intf.getEndpoint(0)
val endpointWriteOut = intf.getEndpoint(1)
val bytes = byteArrayOf(0x57.toByte(), 0x0D.toByte())
thread {
val request = connection.bulkTransfer(endpointWriteOut, bytes, bytes.size, 0)
Log.d(TAG, "Was request to write successful? $request")
val buffer = ByteArray(16)
val response = connection.bulkTransfer(endpointReadIn, buffer, buffer.size, 0)
Log.d(TAG, "Was response from read successful? $response")
val responseString = StringBuilder()
for (i in 0..15) {
responseString.append(buffer[i])
}
Log.d(TAG, "Response: $responseString")
val hex = toHexString(buffer)
Log.d(TAG, "Hex: $hex")
connection.close()
}
fun fromHexString(hexString: String): ByteArray {
val len = hexString.length / 2
val bytes = ByteArray(len)
for (i in 0 until len) bytes[i] = hexString.substring(2 * i, 2 * i + 2).toInt(16).toByte()
return bytes
}
Output:
Was request to write successful? 2
Was response from read successful? 2
Response: 19600000000000000
Hex: 01 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00
There was a couple of missing pieces here. I think the big one was not specifying the baud rate, data bit, stop bit and parity which are all achieved via the controlTransfer function.
In the end I couldn't get it to work myself despite getting successful responses while setting these. Then I found this lovely library which is compatible with this RS232 device and it works well. I just need to specify the vid / pid to get a custom driver using the FtdiSerialDriver class.

Read ITSO smart card information using NFC connection in Android

I am developing an application where i have to read information from ITSO smart card. And it supports below three technologies for filter ACTION_TECH_DISCOVERED.
android.nfc.tech.IsoDep, android.nfc.tech.NfcA
android.nfc.tech.NdefFormatable
Now when I using below code
byte[] apduCmd = {
0x00, //CLA
(byte)0xA4, //INS select
0x00, //P1
0x00, //P2
0x02 //LE
};
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
IsoDep isoDep = IsoDep.get(tag);
try {
isoDep.connect();
byte[] result = isoDep.transceive(apduCmd);
Log.i(TAG, "SELECT: " + bytesToHex(result));
if (!(result[0] == (byte) 0x90 && result[1] == (byte) 0x00)) {
Toast.makeText(this, "Exception occurred!", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "Read successfully!", Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
e.printStackTrace();
}
Above code gives me success bytes i.e. 9000
Now I am not sure what to do next? How to read complete Data/information from this ITSO card. (this card is type of bus ticket).
Any suggestion?
Thanks Michael, i have read the document ITSO specification, and got idea to create command to read the data from the card.
I execute the commands in below sequence.
1) SELECT DIRECTORY- 906A000000
2) SELECT APPLICATION- 905A0000031602A000
3) READ DATA- 90BD0000070400000000000000 (File number- 4)
4) ADDITIONAL FRAME- 90AF000000 (This will execute only if we have Additional frame in response.)
And i am getting response like below for each file ( below response if for file number 4)
Response: 230A00009469FA0798004600002698400100000000000000000000000000000000042C00C0001CDC131089EB4A583BC000000000000000000000000000000000
Now I am not sure how get the information from this?
Can i get all information at once in XML or JSON? Is there any easier way to do this?
Update 10/05/2016
I got the shell information in HEX String, Can you help me to decode the textual information from it. (Reference ITSO specification given above.

Getting data back from bytes

I am continuously getting data from remote bluetooth device which I am storing in a buffer readBuf.
I copy this readBuf to buf.
System.arraycopy(readBuf, 0, buf, 0, readBuf.length);
Now my buf contains data such that -
buf[0] == 0x7D
buf[1] == 0x51
buf[2] == 0x42
...and so on...
I want to log this data to know what is coming from remote bluetooth device.
I tried,
Log.i(TAG, "Buffer Data---- "+Arrays.toString(buf));
But it is not giving data correctly to be 7D 51 42 and so on....
How to get the data in order to log ?
This is working fine -
StringBuffer bufData = new StringBuffer();
for(byte b : readBuf)
{
bufData.append(String.format("%02X", b));
bufData.append(" ");
}
Log.i(TAG, "Data Coming from Remote Device---"+bufData.toString());
Arrays.toString(byte[])
Works fine, although what you are seeing is an signed integer representation of each byte. That's because in Java all integers are signed with a Two's Complement .
You can learn a lot on how to convert bytes to hex in this answer.

BluetoothChat-to-ELM327 split response message

I am attempting to communicate with an ELM327 OBDII Bluetooth dongle using the Android BluetoothChat example. I can connect to the device without any trouble, and messages from BluetoothChat to the ODBII device seem to be transmitted and received by the device correctly.
However, the response messages from the OBDII device are often split into several messages, scrambled, or missing characters.
For example, it takes three tries of the ati command to receive the full expected response:
Me: ati
OBDII: a
OBDII: 327
OBDII: 327
OBDII: 327 v1.5 >
Me: ati
OBDII: 1
OBDII: 1
OBDII: 1.5 >v
OBDII: 1.5 >
Me: ati
OBDII: ELM327 v1.5 >
Similarly, sending 010c should trigger a one line response containing three hex pairs. Instead, I usually (but not always) get results like the following:
Me: 010c
OBDII:
OBDII: 4
OBDII: 3C
OBDII: 3
OBDII: 3C C
OBDII: 3C
OBDII:
OBDII:
OBDII: >
I have tried several different baud rates and different OBDII protocols, but changes from the default settings only seem to make matters worse. Is there a problem with my response message handling? Why is the response message splitting? The Bluetooth dongle works properly with available apps such as Torque, so I don't think the device is malfunctioning.
The code that I'm using is almost identical to the BluetoothChat project (source here). I have only modified the UUID for my Bluetooth device and added a carriage return to the outgoing message (as per this StackOverflow question).
Change 1 (in BluetoothChatService.java):
// Unique UUID for this application
private static final UUID MY_UUID_SECURE =
//UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static final UUID MY_UUID_INSECURE =
//UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66");
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
Change 2 (in BluetoothChat.java):
// The action listener for the EditText widget, to listen for the return key
private TextView.OnEditorActionListener mWriteListener =
new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
// If the action is a key-up event on the return key, send the message
if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) {
String message = view.getText().toString();
//sendMessage(message);
sendMessage(message + "\r");
}
if(D) Log.i(TAG, "END onEditorAction");
return true;
}
};
ELM327 manual for reference
I found a solution to my message splitting problem in this BluetoothSPP project by user akexorcist on Github. The relevant function from class ConnectedThread is presented below:
public void run() {
byte[] buffer;
ArrayList<Integer> arr_byte = new ArrayList<Integer>();
// Keep listening to the InputStream while connected
while (true) {
try {
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);
}
} catch (IOException e) {
connectionLost();
// Start the service over to restart listening mode
BluetoothService.this.start(BluetoothService.this.isAndroid);
break;
}
}
}
Apparently, though please correct me if I'm wrong, .read() cannot grab and maintain the format of whatever bytes appear on the stream without some assistance.

Categories

Resources