HCE on Nexus 7 (2013) with PN532 communication - android

I am communicating between PN532 on Arduino Uno with Nexus 7 running Kitkat 4.4.2,
The HCE program I had from here:
https://github.com/grundid/host-card-emulation-sample
I run the sample program on Nexus 7, and on Arduino I try to send APDU command:
uint8_t PN532::APDU ()
{
uint8_t message[] = {
0x00, /* CLA */
0xA4, /* INS */
0x04, /* P1 */
0x00, /* P2 */
0x07, /* Lc */
0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x00 /* Le */ };
/* Prepare the first command */
/* Send the command */
if (HAL(writeCommand)(message, 13)) {
Serial.println(F("Go here 1"));
return 0;
}
Serial.println(F("Go here 2"));
/* Read the response packet */
return (0 < HAL(readResponse)(message, sizeof(message)));}
Here is my APDU service file: apduservice.html
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="#string/servicedesc"
android:requireDeviceUnlock="false" >
<aid-group
android:category="other"
android:description="#string/aiddescription" >
<aid-filter android:name="F0010203040506" />
</aid-group>
but I cannot get any response from the Nexus 7, and from Nexus 7 I also didn't record any signals? Does anyone know what I am missing here? Thanks

Using the Seeed-Studio PN532 library, you shouldn't need to create your own commands within the library (ie. what you did with uint8_t PN532::APDU () {...}.
Instead, you can use the methods that are already there. To establish a connection with a tag/contactless smartcard (or rather to enumerate the available tags/cards), you would start with inListPassiveTarget(). If the tag/smartcard supports APDUs, it will later automatically be activated for APDU-based communcation. Then you can use inDataExchange() to send and receive APDUs.
So, if you included the PN532 library like this:
PN532_xxx pn532hal(...);
PN532 nfc(pn532hal);
You could then use the library like this:
bool success = nfc.inListPassiveTarget();
if (success) {
uint8_t apdu = {
0x00, /* CLA */
0xA4, /* INS */
0x04, /* P1 */
0x00, /* P2 */
0x07, /* Lc */
0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x00 /* Le */
};
uint8_t response[255];
uint8_t responseLength = 255;
success = nfc.inDataExchange(apdu, sizeof(apdu), response, &responseLength);
if (success) {
// response should now contain the R-APDU you received in response to the above C-APDU (responseLength data bytes)
}
}

Related

Unable to send keyboard events to Bluetooth HID connected device

I am able to connect to the Bluetooth HID device successfully and able to control the paired device home button and navigation buttons.
But unable to send Keyboard key events properly to the HID device. When I am typing something in the host device, the HID device responding with random actions.
I have the following code for the connection with descriptors array,
override fun onServiceConnected(profile: Int, proxy: BluetoothProfile?) {
if (profile == BluetoothProfile.HID_DEVICE) {
mBtHidDevice = proxy as BluetoothHidDevice
val sdp = BluetoothHidDeviceAppSdpSettings(
"HidControl",
"Android HID Joystick",
"Android",
0xC0.toByte(),
descriptor
)
}
}
The descriptor array is as below,
private val descriptor = byteArrayOf( // HID descriptor
0x09, // bLength
0x21, // bDescriptorType - HID
0x11, 0x01, // bcdHID (little endian - 1.11)
0x00, // bCountryCode
0x01, // bNumDescriptors (min 1)
0x22, // bDescriptorType - Report
0x30, 0x00, // wDescriptorLength (48)
// Report descriptor
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Key board)
0xa1.toByte(), 0x01, // COLLECTION (Application)
0xa1.toByte(), 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x04, // USAGE_MAXIMUM (Button 4)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95.toByte(), 0x04, // REPORT_COUNT (4)
0x81.toByte(), 0x02, // INPUT (Data,Var,Abs)
0x75, 0x04, // REPORT_SIZE (4)
0x95.toByte(), 0x01, // REPORT_COUNT (1)
0x81.toByte(), 0x03, // INPUT (Cnst,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, 0x81.toByte(), // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95.toByte(), 0x02, // REPORT_COUNT (2)
0x81.toByte(), 0x02, // INPUT (Data,Var,Abs)
0xc0.toByte(), // END_COLLECTION
0xc0.toByte() // END_COLLECTION
)
Code to send keyboard events to the target device is below
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
Log.d("Key Codes ", "$keyCode + event: $event")
for (btDev in mBtHidDevice!!.connectedDevices) {
mBtHidDevice!!.sendReport(
btDev, 0, byteArrayOf(event!!.keyCode.toByte())
)
mBtHidDevice!!.sendReport(
btDev, 0, byteArrayOf(
0
)
)
}
return super.onKeyUp(keyCode, event)
}
Please suggest if I am missing anything here. Thanks for the help!
You need to use Keyboard Usage Page.
The logical minimum and logical maximum that I see is only from 1 to 4. You wanted those USAGEs alone?
Refer to HID usage table https://www.usb.org/document-library/hid-usage-tables-122
There is a Keyboard use case in the appendix. You can refer to that.

Android BLE: Is it possible to add Service Data and Manufacturer Data at the same time when advertising an iBeacon packet?

I'm currently doing an experiment in order to trigger a beacon detection device. Here is the sample of a detected beacon that can be used to trigger that device.
In my experiment, I'm trying to replicate the beacon like in the above picture by using Android BLE library and using iBeacon protocol, since the detection device claims that it follows iBeacon protocol. First, I try to set the service UUID and service data by using AdvertiseData object, then advertise it. The code roughly looks like this:
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
byte[] experimentData = {0x48, 0x6E, (byte) 0xDD, 0x2A, 0x40, (byte) 0xA6, (byte) 0xF0, 0x07, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00};
byte[] uuidBytes = {0x10, 0x02}
byte[] advertisingBytes = getAdvertisingBytes();
ParcelUuid parcelUuid = parseUuidFrom(uuidBytes);
dataBuilder.addServiceData(parcelUuid, experimentData);
dataBuilder.addServiceUuid(parcelUuid);
dataBuilder.setIncludeTxPowerLevel(false);
dataBuilder.setIncludeDeviceName(false);
//dataBuilder.addManufacturerData(manufacturerCode, advertisingBytes);
AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
settingsBuilder.setAdvertiseMode(0);
settingsBuilder.setTxPowerLevel(3);
settingsBuilder.setConnectable(false);
bluetoothLeAdvertiser.startAdvertising(settingsBuilder.build(), dataBuilder.build(), null);
I commented the addManufacturerData() part for now. The result looks like this.
Now I modify the code so that instead of using Service UUID and Service Data, I use addManufacturerData to advertise the data. The code looks like this:
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
byte[] experimentData = {0x48, 0x6E, (byte) 0xDD, 0x2A, 0x40, (byte) 0xA6, (byte) 0xF0, 0x07, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00};
byte[] uuidBytes = {0x10, 0x02}
byte[] advertisingBytes = getAdvertisingBytes();
//ParcelUuid parcelUuid = parseUuidFrom(uuidBytes);
//dataBuilder.addServiceData(parcelUuid, experimentData);
//dataBuilder.addServiceUuid(parcelUuid);
//dataBuilder.setIncludeTxPowerLevel(false);
//dataBuilder.setIncludeDeviceName(false);
dataBuilder.addManufacturerData(manufacturerCode, advertisingBytes);
AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
settingsBuilder.setAdvertiseMode(0);
settingsBuilder.setTxPowerLevel(3);
settingsBuilder.setConnectable(false);
bluetoothLeAdvertiser.startAdvertising(settingsBuilder.build(), dataBuilder.build(), null);
The result is shown below. The "Service Data" part is gone, and it is now recognized as an iBeacon packet:
Now, in the first picture, there are "Service Data" section and "Beacon" section, so I though that by adding Service Data and Manufacturer Data, the two section will be shown. I uncomment all of the code, and now it looks like this:
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
byte[] experimentData = {0x48, 0x6E, (byte) 0xDD, 0x2A, 0x40, (byte) 0xA6, (byte) 0xF0, 0x07, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00};
byte[] uuidBytes = {0x10, 0x02}
byte[] advertisingBytes = getAdvertisingBytes();
ParcelUuid parcelUuid = parseUuidFrom(uuidBytes);
dataBuilder.addServiceData(parcelUuid, experimentData);
dataBuilder.addServiceUuid(parcelUuid);
dataBuilder.setIncludeTxPowerLevel(false);
dataBuilder.setIncludeDeviceName(false);
dataBuilder.addManufacturerData(manufacturerCode, advertisingBytes);
AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
settingsBuilder.setAdvertiseMode(0);
settingsBuilder.setTxPowerLevel(3);
settingsBuilder.setConnectable(false);
bluetoothLeAdvertiser.startAdvertising(settingsBuilder.build(), dataBuilder.build(), null);
But then the advertising packet does not shown at all in the beacon detection app. No exception either, so I don't know whether the beacon is advertised or not
So, it is possible by using Android BLE library to replicate beacon as shown in the first picture (Service data and beacon/manufacturer data in one packet)?
A single advertisement packet is limited to about 23 data bytes so it does not have room for both manufacturer data and service data of the sizes you have in your example.
Try advertising both at the same time each in its own advertisement. Android devices support transmitting multiple advertisements simultaneously.

How can I use Arduino NFC to receive a key from Android and respond if valid?

I try to create an Android app that sends a key to an Arduino NFC Shield. I am able to send the key from the mobile and turn on the LED on the Arduino. But I don't know how to make the NFC shield send back to the Android device a response: valid key or not.
I get the message on Arduino, I am able to turn on the LED when the key is correct. The problem is that I need the NFC Shield to send back a message to the mobile phone, so that the app knows everything worked as expected or not.
I use NFC Shield PN532 (with Adafruit_PN532) in SPI mode.
success = nfc.inListPassiveTarget();
if(success) {
Serial.println("Found something!");
uint8_t selectApdu[] = {
0x00, /* CLA */
0xA4, /* INS */
0x04, /* P1 */
0x00, /* P2 */
0x05, /* Length of AID */
0xF2, 0x22, 0x22, 0x22, 0x22};
uint8_t response[255];
uint8_t responseLength = sizeof(response);
success = nfc.inDataExchange(selectApdu,
sizeof(selectApdu), response, &responseLength);
if(success) {
if(validKey(response, responseLength)){
Serial.println("Acces GRANTED.");
accesGranted();
}else{
Serial.println("Acces DENIED!!!!!!!!!!!!!!!!\n");
}
}
else{
Serial.println("Failed sending SELECT AID");
}
}

Control relay over USB from Android

I have this USB Relay and I'd like to control from an Android phone.
(There is a similar post here but it explains how do it from a Linux shell. By looking at that code i figured i'd be able to solve it - apparently not.)
The device lists in lsusb:
Bus 002 Device 011: ID 16c0:05df VOTI
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x16c0 VOTI
idProduct 0x05df
bcdDevice 1.00
iManufacturer 1
iProduct 2
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 34
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 20mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0 No Subclass
bInterfaceProtocol 0 None
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.01
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 22
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 20
I find it strange that the end point is defined as "EP IN". In my mind it should be "EP OUT" since the direction should be "host->device".
Anyway, I use the Android USB manager to create a connection and then initialize the USbRequest for an interrupt based end point. Android permissions and all that is handled so the device is connected successfully.
Snippet for sending data. It runs in a separate thread following the Android guidelines:
UsbRequest request = new UsbRequest();
synchronized (mUsbLock) {
if (mUsbConnection != null && mUsbEndPointIn != null) {
if (!request.initialize(mUsbConnection, mUsbEndPointIn)) {
Log.e(TAG, "Unable to initialize UsbRequest. Thread exits");
return;
} else {
if (DEBUG) {
Log.d(TAG, String.format("Usb request is initialized"));
}
}
} else {
Log.e(TAG, "Usb communication is not up and running. The worker thread should never be started.");
return;
}
}
mRunning.set(true);
while (mRunning.get()) {
if (DEBUG) {
Log.d(TAG, String.format("Waiting for data to be sent to end point"));
}
WorkPackage wp = mWorkQueue.take();
// send the package.
byte[] data = wp.getData();
if (!request.queue(ByteBuffer.wrap(data), data.length)) {
Log.e(TAG, "Unable to queue to send data on UsbRequest.");
continue;
} else {
if (DEBUG) {
Log.d(TAG, String.format("Usb request is queued on end point, ep=%s", printUsbEndpoint(mUsbEndPointIn)));
}
}
}
It seems everything is fine, no errors occur and the request is queued on the end point but then nothing happens at all. I don't get any message back that the request has been handled.
Since the supplier won't release the on/off commands I tried variants based on the Linux post (above). None seem to work though. Supplier only release Windows binary lib.
Sending 8 byte packages (according to max package):
public static byte[] SET_RELAY_ON = {(byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
public static byte[] SET_RELAY_OFF = {(byte) 0xfd, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
Help appreciated.
So, i figured out how to do this. I will write the solution here in case someone else is having a similar problem.
I had to snoop the USB traffic to understand what to actually send. It turned out that the defined interrupt end point was not used at all. So, the communication with the device was not interrupt based but instead using the control transfer type on end point 0.
So, using the Android USB API this translates into:
Open device (device->host direction):
int r = mUsbConnection.controlTransfer(0xa1, 0x01, 0x0300, 0x00, buffer, buffer.length, 500);
Open relay '1' (host->device direction).
byte[] buffer = {(byte) 0xff, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
int r = mUsbConnection.controlTransfer(0x21, 0x09, 0x0300, 0x00, buffer, buffer.length, 500);
Note, the second parameter in the buffer (0x01) is the relay number (in case you have >1 relay on the board). I only had one.
close relay '1' (host->device direction):
byte[] buffer = {(byte) 0xfd, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
int r = mUsbConnection.controlTransfer(0x21, 0x09, 0x0300, 0x00, buffer, buffer.length, 500);
I have found the project in Github which is similar with this it (for who is looking it)
https://github.com/gigacycle/AndroidHidUsbRelayControl
I have tested this code and I can confirm that it works well with the USB relay board.

AOA 2.0 HID Device Unsupported Control Request On Sending HID Event

I am trying to use the AOA 2.0 protocol and libusb to send key presses to an Android device. I am able to put the device accessory mode and and able to register the HID device. However whenever I send an event I get the error:
libusb: debug [handle_control_completion] unsupported control request
I think my problem may be the hid descriptor that I am sending, however I found one online that should work.
Here is my relevant code with the descriptor:
char DESC[] = {
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x06, /* Usage (Keyboard) */
0xA1, 0x01, /* Collection (Application) */
0x05, 0x07, /* Usage Page (Keyboard) */
0x19, 224, /* Usage Minimum (224) */
0x29, 231, /* Usage Maximum (231) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x08, /* Report Count (8) */
0x81, 0x02, /* Input (Data, Variable, Absolute) */
0x81, 0x01, /* Input (Constant) */
0x19, 0x00, /* Usage Minimum (0) */
0x29, 101, /* Usage Maximum (101) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 101, /* Logical Maximum (101) */
0x75, 0x08, /* Report Size (8) */
0x95, 0x06, /* Report Count (6) */
0x81, 0x00, /* Input (Data, Array) */
0x05, 0x08, /* Usage Page (LED) */
0x19, 0x01, /* Usage Minimum (1) */
0x29, 0x05, /* Usage Maximum (5) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x05, /* Report Count (5) */
0x91, 0x02, /* Output (Data, Variable, Absolute) */
0x95, 0x03, /* Report Count (3) */
0x91, 0x01, /* Output (Constant) */
0xC0 /* End Collection */
};
int response;
//Register the HID device
response = libusb_control_transfer(handle, 0x40, 54, 1, sizeof(DESC), NULL, 0, 0);
if (response < 0) {error(response); return -1;}
// Send the device descriptor
response = libusb_control_transfer(handle, 0x40, 56, 1, 0, DESC, sizeof(DESC), 0);
if (response < 0) {error(response); return -1;}
usleep(1000);
// OK so here is the problem, this request should just send the next song ket
// However I am getting unsupported control request.
char report[] = {0x07,0x00,0xEC,0x00,0x00,0x00,0x00,0x00};
response = libusb_control_transfer(handle, 0x40, 57, 1, 0, report, sizeof(report), 0);
if (response < 0) {error(response); return -1;}
return 0;
EDIT: Ok so I did some more digging around in the android adk code and I found a generic keyboard descriptor with some sample code. Now it seems to not fail like one out of every 10ish attempts which is very weird? I updated the code as well.
My problem was that I did not sleep long enough after sending the device descriptor.
usleep(100000);
Fixed it

Categories

Resources