9

JavaEE, JavaFX and RFID - Part 2: Reading RFID from Java

 3 years ago
source link: http://fxapps.blogspot.com/2014/08/javaee-javafx-and-rfid-part-2-reading.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
Hello, continuing our series of posts about RFID and JavaFX, today we are going to show you how we read the RFID tag information from the receptor using Java. Remember we are using the RFID USB Starter Kit, the information of this post is specific for this kit, however, I believe most of the information applies to others RFID readers.

Part 1: The Application
Part 2: Reading RFID from Java 
Part 3: REST API and Security
Part 4: The Client

The RFID reader

RFID is simply an identification that will be read using a Radio Frequency. The ID is in RFID tags which can be read using a RFID Reader. My purpose is only read the tag, so we won't go deep in the writing part, we will focus on reading a RFID tag.

I used the simplest RFID Reader I could find since I was avoiding unnecessary trouble. The reader is connected by USB and we just have to connect it to a PC so we can start hearing the buzz when we approach a RFID tag to the reader.

DSC00137.JPG

Notice that the reader and the tags have some conditions such as frequency of operation. I won't go deep on these details on this post.
The reader I bought is integrated with the FTDI chip and it has total support for installation in the popular operating systems we have. Notice that the main duty of this chip was to interface the old RS232 interface with USB, so we need a driver.

Installing the library(driver)

Initially I found some issues to install the driver so I can perform the communication with the chip and simply read the incoming data. In another scenarios, it's usual to also write data, but today we will only read.
First thing I did was to download the driver on D2XX web page, then I followed the instructions on the installation guide for linux, which was basically was run the following commands:

sudo cp /releases/build/arch/lib* /usr/local/lib
cd /usr/local/lib 
sudo ln –s libftd2xx.so.1.1.12
libftd2xx.so 
sudo chmod 0755 libftd2xx.so.1.1.12 

* arch is the architecture of my operating system.

After this, I could see that a new directory was created under /dev when I connected my RFID reader using the USB cable:
Screenshot+from+2014-07-26+17:35:28.png
So I opened the file(well, actually a symlink) under serial/by-id directory and I was able to read the content of my RFID when I approached the RFID tag to the reader:
Screenshot+from+2014-07-26+17:38:23.png
After setting native stuff, it was time to find a way to read it from Java!

Reading FTDI from Java

In D2XX page we can find two libraries to read it from Java, however, I tried to use these and I had issues. The main issue was related to the native part and, as I said, I didn't want to waste time on this...
Well, everything is a file in Linux, remember we were reading data using cat command. Why not read the content of that file from Java? Having this in mind, I created a simple program to read the content of that file, see the code:

package org.jugvale.rfid;

import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; import java.util.List; import java.util.Scanner; import java.util.stream.Collectors;

/** * Will read the file created by FTDI when a compatible chip is connected to a * Linux machine using the USB port * * @author william * */ public class LinuxFTDISerialReader { private static final String DEFAULT_DEVICE_BASE_PATH = "/dev/serial/by-id"; private String deviceBasePath; public static final String DEFAULT_ERROR_MESSAGE = "Device not found. Check if a device is connected, the driver FTDI was correctly installed and if the device base Path is right(default is " + DEFAULT_DEVICE_BASE_PATH + ")";

public LinuxFTDISerialReader() { deviceBasePath = DEFAULT_DEVICE_BASE_PATH; }

public LinuxFTDISerialReader(String deviceBasePath) { this.deviceBasePath = deviceBasePath; }

public List<Path> getAvailableDevices() throws IOException { List<Path> deviceList = Collections.emptyList(); try { deviceList = Files.list(Paths.get(deviceBasePath)).collect( Collectors.toList()); } catch (Exception e) { e.printStackTrace(); throw new IOException(DEFAULT_ERROR_MESSAGE, e); } return deviceList; }

/** * Will lock the thread reading the device. Should be executed in a * separated thread! * * @param device * @return * @throws IOException */ public String waitAndRead(Path device) throws IOException { if (device == null || !Files.exists(device)) { throw new IOException("Device should not be null!"); } Scanner scanner = new Scanner(device); String rfid = null; while (scanner.hasNextLine()) { rfid = scanner.nextLine(); if (rfid != null && !rfid.trim().isEmpty()) break; } scanner.close(); return rfid.substring(1); } }

Notice that it keeps the file open and busy(see method read), so it's not recommended to continuously read the file as did for test. A better implementation would be using the "new" WatchService, but it seems it doesn't work for symbolic links!

A reader from JavaFX

I tried to create a control that will perform the read for me. It's specific to the conditions I showed above, so I think it's not too reusable...
What I have it's a dialog and it lists the devices and then I can choose a device. After I choose it, it will accumulate the RFIDs that were read into a List. When you click a button, the dialog will dispose and a list of the read RFID will be available to the caller... See the source here and a screenshot:

package org.jugvale.rfid.ui;

import java.io.IOException; import java.nio.file.Path; import java.util.concurrent.ExecutionException; import java.util.function.Consumer;

import javafx.concurrent.Task; import javafx.scene.control.Label; import javafx.scene.control.ListView; import javafx.scene.control.TitledPane; import javafx.scene.input.MouseEvent; import javafx.scene.layout.StackPane;

import org.jugvale.rfid.LinuxFTDISerialReader;

/** * @author william * */ public class FTDIReaderPane extends TitledPane {

LinuxFTDISerialReader reader = new LinuxFTDISerialReader(); ListView<Path> listDevices; /** * To be invoked when we read the RFID */ Consumer<String> onRead; Consumer<String> onError;

private Path selectedDevice;

public FTDIReaderPane() { this(null, null); } public FTDIReaderPane(Consumer<String> onRead, Consumer<String> onError) { super(); this.onRead = onRead; this.onError = onError; settings(); initComponent(); }

public void setOnRead(Consumer<String> onRead) { this.onRead = onRead; }

public void setOnError(Consumer<String> onError) { this.onError = onError; }

/** * * Will show up and read a RFID tag, but it will always ask to select a tag * * @throws IOException * Error when it can't read the device */ public void askForDeviceAndReadTag() { try { if (selectedDevice == null) fillDevices(); else { readDevice(); } setVisible(true); } catch (Exception e) { e.printStackTrace(); fail(LinuxFTDISerialReader.DEFAULT_ERROR_MESSAGE); } }

private void settings() { setText("Read RFID Tag"); setMaxHeight(200); setMaxWidth(300); setStyle("-fx-stroke-width: 20;"); setCollapsible(false); setVisible(false); }

private void initComponent() { StackPane root = new StackPane(); Label lblPassCard = new Label("Pass RFID Card"); lblPassCard.setStyle("-fx-font-size: 20px; -fx-font-weight: bold"); listDevices = new ListView<>(); listDevices.setOnMouseReleased(this::newDeviceSelectedAction); root.getChildren().addAll(listDevices, lblPassCard); lblPassCard.visibleProperty().bind(listDevices.visibleProperty().not()); this.setContent(root); }

private void newDeviceSelectedAction(MouseEvent e) { Path selectedPath = listDevices.getSelectionModel().getSelectedItem(); if (selectedPath != null) { listDevices.setVisible(false); listDevices.getSelectionModel().clearSelection(); selectedDevice = selectedPath; readDevice(); return; } }

private void fillDevices() throws IOException { listDevices.setVisible(true); listDevices.getItems().setAll(reader.getAvailableDevices()); listDevices.getSelectionModel().clearSelection(); }

private void readDevice() { new Thread(new Task<String>() { @Override protected String call() throws Exception { return reader.waitAndRead(selectedDevice); }

@Override protected void succeeded() { try { success(this.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } setVisible(false); }

@Override protected void failed() { fail(LinuxFTDISerialReader.DEFAULT_ERROR_MESSAGE); setVisible(false); selectedDevice = null; } }).start(); } private void success(String value) { if(onRead == null) { throw new Error("You must set an onRead funcion"); } onRead.accept(value); } private void fail(String value) { if(onError == null) { throw new Error("You must set an onError funcion"); } onError.accept(value); } }

rfid_read.png
rfid_select_device.pngrfid_waiting.png

Conclusion

Read RFID from Java is not a hard task on Linux. It could be, however, simpler if we had a library to make the operations for us.

Source Code on github


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK