Skip to content

A Xamarin port of the usb-serial-for-android library

Back in January, I ported the excellent usb-serial-for-android library from the Java source code to Xamarin C#.  We have an Android application that needs to use an external RFID reader.  The reader is an Elatec TWN4 RFID reader and it can work as virtual comm port over USB. To use that reader, I needed a general purpose serial over USB library.  I ended taking a very good one from the open source Java community and porting it over to C#. That ported library is up on Github under the name UsbSerialForAndroid.

Out of the box, Android doesn’t come with a lot of support for serial port devices.  It’s probably not a common use case.  Starting in Android 3.1, support was added for USB Host mode to allow access to USB devices from Android apps.  There was enough of a need for serial devices that Mike Waverly wrote a very good library in Java named usb-serial-for-android.  It supports many of the common USB serial chipsets.  So I wanted to use that.

With Xamarin Android, you have basically two ways of consuming Java libraries.  You can use them directly by creating a C# to Java wrapper and bundling the .jar file with your project.  While that can work, and work very well, it can also be a bit clunky and you can hit some issues mapping the Java method calls to C#.  Another group had gone down that path.  They implemented a wrapper for the .jar file and added some helper classes.  It looked like their project was abandonware and was not using a current version of Mike’s code.  You would also have the limitation of not being to debug into that code library.

If you have the source code, you can port the code from Java to C#.  I decided to go down that route.  It took a couple of days, but I was able to port all of the Java code to C#.  It went over more or less as is.  Some changes needed to made because reflection is handled differently in C# than in Java.  There were also a bug in Xamarin’s API access code that mangled the array handling in some Java code.

In Java, ByteBuffer.wrap(someBuffer) allows for two-way updating of a Java array with a stream buffer,  A bug in Xamarin’s API mapping tool emits code that allocates a new buffer when you call Wrap.  Changes made to the ByteBuffer are not reflected in the original byte array.  This is logged in Xamarin’s Bugzilla database here and here.

In the CdcAcmSerialPort.Read() method, defined here in C# and here in Java, I needed to add a line to copy the new array back over the original array.

In the original Java (edited) code, we had this
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, dest.length)) {
throw new IOException("Error queueing request.");
}

final int nread = buf.position();
if (nread > 0) {
return nread;
}

In the C# code, I added a call to BlockCopy to overwrite the original byte array with the updated contents
ByteBuffer buf = ByteBuffer.Wrap(dest);
if (!request.Queue(buf, dest.Length))
{
throw new IOException("Error queueing request.");
}

int nread = buf.Position();
if (nread > 0)
System.Buffer.BlockCopy(buf.ToByteArray(), 0, dest, 0, dest.Length);
return nread;
}

I also replaced some integer constants with enumerated types where it made sense to do so. I also took the C# helpers from the LusoVU repository.

As much as I could do so, I followed the code structure’s of the Java library.  When changes are made to that library, I can view those changes and make the equivalent changes in the C# code.  The end result was that I ended up with all C# code and it works great.

The TWN4 has become my favorite RFID reader.  It’s very good at reading different card types and you can write custom firmware for it in C.  I used it in another project where it had to work with a custom protocol to with the host device.

TWN4 reader