I'm trying to read data from the custom made USB device (working as slave) in Android. I was able to write the data to the device with this code:
UsbRequest request = new UsbRequest();
request.initialize(_outConnection, _outEndpoint);
int bufferDataLength = _outEndpoint.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1);
buffer.put(bytes);
if (request.queue(buffer, bufferDataLength)) {
UsbRequest req = _outConnection.requestWait(); }
I see the result on the debug board that my device is connected to.
I'm trying the same approach for reading data, but apparently that doesn't work:
int siz = 1;
ByteBuffer res = ByteBuffer.allocate(siz + 1);
UsbRequest request = new UsbRequest();
request.initialize(_inConnection, _inEndpoint);
request.queue(res, siz); // This return false always
What am I doing wrong? I have no idea of the size of the packet sent back - but I assume that 1 byte I would be always able to read.
My device has HID interface with two interrupt endpoints (IN and OUT)
I have no idea what fixed the problem, but now it works. I have rewritten everything from scratch. I think I didn't use this code (I thought it is for user notification and I don't need that. But appears it is something else) - and that was the main reason why it didn't work:
// Create and intent and request a permission.
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(_context, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
_context.registerReceiver(mUsbReceiver, filter);
Several things that I did and which helped me to implement stable connection are:
1) Closing and opening the connection each time I need it. I know this is sounds strange, but this is the only way I could make it stable. If I try to use long-living connection, for some reason it gets corrupted and stops from working after some time.
2) Reading continously in never-ending while loop. I also put some short sleeps in all my threads - that helped to read in more real time manner.
3) Locking the device (synchronized). I do not open both write and read connections simultaneously.
I didn't have much hours assigned for this project, and this project is only a demo - so all of this suited us well. I think if spent a little more time, some of these things could have been rewritten to more nice ones.
Related
I'm a beginner with Android developement and I'm trying to configure a "pass-through" mode for NFC. Basically I2C writes something on an NFC TAG, Mobile Phone picks it up, new data is written by I2C and so on. I kind of struggle with the time the tag is written: Meanwhile, the phone gets an "NAK" and throws back an IOException since transceive fails. How can I properly handle it? I tried with "thread.millis" to wait till I2C is done, but this solution looks pretty crappy and only works with my arduino and phone.
while (Schleife < 1000) {
try {
answer = ultralight.transceive(command); //This one throws an IOException if the data is not ready yet
Schleife = Schleife + 1;
} catch (IOException ioe) {
//Log.e("UnsupportedEncoding", ioe.toString());
}
}
I want the program to re execute the process. One thing I tried was to include the catch statement into the while-loop, but it took forever sometimes to rerun the while loop.
I'm thankful for every answer.
Kind regards
My reading of the datasheet for the chip is that you are looping around transceiving the wrong command.
After a READ or FAST_READ command involving the terminator page of the SRAM, bit SRAM_RF_READY and bit RF_LOCKED are automatically reset to 0b allowing the I2C interface to further write data into the SRAM buffer.To signal to the host that further data is ready to be written, the following mechanisms are in place:•The NFC interface polls/reads the bit SRAM_RF_READY from NS_REG (see Table14) to know if new data has been written by the I2C interface in the SRAM
You loop should be read E8h block and checking the to see if the SRAM is ready to be read by the RF connection, then read 64 bytes with fast read when the right bits are set in byte 0
This is how the chip implements a flow control mechanism between the I2C interface and the RF interface to prevent errors.
update
Ok the implementation sheet shows how to do it without flow control.
For the question how to handle a NACK, first you need to check for it
Below is how I check for a NACK
if ((answer != null) && (answer.length == 1) && ((answer[0] & 0x00A) != 0x00A)) {
// Got NACK
Log.e("Nack", Schleife); //added to identify iteration.
}
It would be helpful to also log the iteration number of any IOException
I'm thinking that the NACK and IO exception are on different iterations.
As a proper NACK is not an IO Exception.
Also Android code the anticollision under the hood, so the only thing you can try when receiving the NACK is close and connect again.
or
A low level transeive to "0x95 0x70 (UID bytes)" be correct
(taken from https://android.googlesource.com/kernel/common/+/android-3.18/net/nfc/digital_technology.c#349 )
"0x95 0x70" I think is the correct Anti-collison command for the card type.
I am trying to read a message from RFID reader connected via USB to windows 10pro machine with usb4java library.
I have managed to claim the interface, opened pipe and registered listener for the data, however the listener is never triggered. The reader acts as keyboard and whatever it reads ends up in active application, such as IDE i have open, instead of in listener.
UsbInterface usbInterface = activeInteface(device);
// there is only one endpoint in the list
UsbEndpoint endpoint = (UsbEndpoint)usbInterface.getUsbEndpoints().get(0);
UsbPipe pipe = endpoint.getUsbPipe();
try {
usbInterface.claim();
// true
System.out.println("claimed usb interface: " + usbInterface.isClaimed());
pipe.open();
// true
System.out.println("pipe open: " + pipe.isOpen());
pipe.addUsbPipeListener(new MessageListener());
// true
System.out.println("pipe active: " + pipe.isActive());
// keep main thread alive, async call should be done from another thread i guess
Thread.sleep(15000);
}
catch (Exception any) {System.out.println(any);}
}
And the listener:
private static class MessageListener implements UsbPipeListener {
#Override
public void errorEventOccurred(UsbPipeErrorEvent event) {
System.out.println(event.toString() + " , " +event.getUsbException());
}
#Override
public void dataEventOccurred(UsbPipeDataEvent event) {
// this code block never triggers
System.out.println("listener ...);
int actualLength = event.getActualLength();
System.out.println("length: " + actualLength);
byte[] data = event.getData();
System.out.println("data length " + data.length);
}
}
i have also tried synchronous read instead of asynchronous in the block above, like this:
byte[] buffer = new data[8];
// this fails on its own, don't even need to read something with RFID reader
int received = pipe.syncSubmit(buffer);
fails with:
USB error1: Transfer error on interrupt endpoint: Input/Output error
There is some windows specific property that library supports: org.usb4java.javax.useUSBDK = true
but this fails when i try to set it with an exception.
I have 0 experience with USB devices so not sure how to proceed from here. Is there something wrong with the code, do i need USBDK or device does not support libUSB driver ? Sadly this is not my device and i don't have access to documentation of the device so cannot be sure if it is device driver issue.
I know that this is 2 years old, but i've had similar issue and this was one of the first questions that i ran into looking for solution, which took me hours.
So, basically, windows doesn't let to read/write keyboard devices directly, to do so, you have to override it's driver (That's why you're getting Input/Output error, and it's written in the hid4java's FAQ).
First way to override device driver is described in libusb wiki.
As far as i know you would have to install a new driver every time you connect the device to a new USB port, which is why i recommend you to read further.
Second way is what you've already mentioned, which is using UsbDk (Usb Drivers Development Kit for Windows). It makes the device accessible for you by detaching the kernel driver and reattaching it back after you're done playing with it.
In order to use it, you need to do two things:
Set the org.usb4java.javax.useUSBDK = true in you javax.usb.properties file as stated in the manual (this can also be done manually in low-level usb4java, see OPTION_USE_USBDK and setOption(Context, int)).
Download and install UsbDk on your system (simplest way is to download x64 or x86 version msi installer which has GUI and is fully automated), which is sadly not in the manual (maybe it's obvious for some people, but took me amount of time that i am not proud of to realize).
Im guessing that the lack of second step is why OP has been getting an exception.
Hope that this will help someone, knowing all this two days ago would save me a lot of headache.
RFID readers operate in keyboard emulation mode by default.
You can normally get a tool from the manufacturer's website to configure the RFID reader.
This will allow you to change the reader to HID mode.
This should resolve your issues.
Sorry for the late response but I hope it helps others.
Let me get straight to an example to explain further.
final var socket = new java.net.ServerSocket(1234);
for (;;)
{
try (final var client = socket.accept())
{
client.getOutputStream().write("HTTP/1.1 200 OK\r\n\r\n".concat(java.time.Instant.now().toString()).getBytes());
}
}
When I now open my browser of choice (Firefox cough) I'll receive the current time and date. The question now is how I can write to that socket at a later point in time.
hypothetical solution
Here's something I already tried, but doesn't work at all.
final var socket = new java.net.ServerSocket(1234);
for (;;)
{
try (final var client = socket.accept())
{
client.getOutputStream().write("HTTP/1.1 200 OK\r\n\r\n".concat(java.time.Instant.now().toString()).getBytes());
client.getOutputStream().flush();
Thread.sleep(1000L);
client.getOutputStream().write("And another paragraph.".getBytes());
}
}
The result is a web page loading for approximately a single second, printing out the following result (may vary due to different date and time on your end).
2019-01-19T18:19:15.607192500Z
And another paragraph.
Instead I would like the see something like that:
print out the current time and date.
wait a second without the content of the web page changing.
print out the next paragraph.
How would I go about implementing that?
Is it possible for the server to write text into a web page after it is loaded? Yes it definitely is, but these days I suspect it it is rarely done. I started web development in the 1990s and back then that was a pretty common technique. We used it to write live chat messages to browsers with no Javascript. These days Javascript is ubiquitous and powerful, so using client-side Javascript to update a page will be the best option in most cases.
That said, the technologies we used for writing server-side updates back then should still work now. I suspect the reason you don't see updates in your browser is because it doesn't know it should start displaying the page before everything is loaded. Using chunked transfer encoding, a 1990s technology still supported by modern browsers, should resolve that. It it allows the server to indicate when a 'chunk' of data is complete and browsers will generally process each chunk immediately rather than wait for all the chunks to arrive.
The easiest way to use chunked transfer encoding is to use an HTTP library like Apache HttpComponents, then wrap your output stream in the appropriate class:
final var socket = new java.net.ServerSocket(1234);
for (;;)
{
try (final var client = socket.accept())
{
var outputStream = new ChunkedOutputStream(client.getOutputStream());
outputStream.write("HTTP/1.1 200 OK\r\n\r\n".concat(java.time.Instant.now().toString()).getBytes());
outputStream.flush();
Thread.sleep(1000L);
outputStream.write("And another paragraph.".getBytes());
}
}
Edited to clarify my intent: (based on initial answers)
I have a web app. The server consists of a set of Java POJOs and I'm using Jersey to expose these as REST APIs. The browser calls these APIs, using jquery ajax, and does stuff.
I want to log the duration that my ajax queries take, and I want a break down by
How long it took to send the query from browser to server (into my Java POJO)
How long it took for the Java POJO to process the request
How long it took for response to be transmitted to browser (from POJO exit point to onComplete: entry point in javascript)
I'm also looking for a code based solution that I can apply systematically across my app.
So, 2 on its own is trivial, and timing the whole sequence is trivial. But I'm not sure about getting the breakdown for 1 & 3. I was initially going to pass the system time as a GET param, and compare to currentTimeMillis on the server - but this relies on the browser system time being in sync with the server system time. Unlikely to be reliable.
Are there any other suggestions?
See "How do you determine exactly when, accounting for network latency, a HTTP request was sent?", the answer explains how you can "calibrate" the client-side time with the server-side time. Note that this calibration will not be exact. Hope this helps.
Use Fiddler.
The answer is you can't. Certainly not from within a browser using Ajax.
The server could put the processing time in a custom response header, the client knows the send/receive times, from this it easy to derive the round trip time and assumes symmetrical link performance.
Going beyond that effectively means you want to measure TCP performance.
If this is only for a couple of pages and a couple of calls i would suggest using Network tab in Chrome Dev Tools. It provides plenty of info.
Is this something that you are looking for...
function myAjax(){
var timer = {};
timer["start"] = new Date().getTime();
if(window.XMLHttpRequest){
var req = new XMLHttpRequest();
}
else{
var req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.onreadystatechange=function(){
if(req.readyState===2){
timer['recieved'] = new Date().getTime() - timer['start'];
}
if(req.readyState===3 && !timer['processing']){
timer['processing'] = new Date().getTime();
}
if(req.readyState===4 && req.status===200){
timer['processing'] = new Date().getTime() - timer['processing'];
timer['full'] = new Date().getTime() - timer['start'];
console.log(timer);
}
}
req.open("get", "myScript.php", true);
req.send();
}
Times are held in the timer variable. This obviously is not exact and may not even be what you are looking for, but is a simplified version of some AJAX times.
This is odd. I am trying to set up Bluetooth SPP on a Droid X Android 2.3.4. I have included a few different methods from attempting to open an rfcomm Socket, one being reflection (needed for support of certain phones)
However, with the Droid X a strange thing happens. When I connect the first time to a Bluetooth device my app opens up and attempts SPP by first:
Method m = mmDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
mmSocket = (BluetoothSocket) m.invoke(mmDevice, Integer.valueOf(1));
And if it can't find the method, it tries the normal
mmSocket = mmDevice.createRfcommSocketToServiceRecord(SerialPortServiceClass_UUID);
This works correctly the first time through. But if I close my program then reopen it for some reason the reflection method then actually finds the method, attempts to connect doesn't have any errors, but it doesn't actually connect.
If I close the app, power cycle the bluetooth adapter on the phone and try again it will work correctly.
I am at a loss on what's going on, so any help would be greatly appreciated.
Well I came up with a bandaid type fix that I am not happy with, but will work until I can find the root cause or better solution. I simply make a shared preference object that contains a "level" of which methods to try.
The levels are labeled 1-4, and if the level is set to a number <= to the current level it will try that method if no connection has been established.
if(level<=1){
success set level = 1
fail set level = 0
}
if(level<=2){
success set level = 2
fail set level = 0
}
...
if(level<=4){
success set level = 4
fail set level = 0
}