org.bidib.jbidibc.scm.HotPlugEventWatcher Maven / Gradle / Ivy
package org.bidib.jbidibc.scm;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.SwingUtilities;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.bidib.jbidibc.core.utils.ByteUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.serialpundit.core.SerialComException;
import com.serialpundit.usb.ISerialComUSBHotPlugListener;
import com.serialpundit.usb.SerialComUSB;
import com.serialpundit.usb.SerialComUSBdevice;
public class HotPlugEventWatcher implements ISerialComUSBHotPlugListener, Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(HotPlugEventWatcher.class);
// private SerialComManager scm;
private SerialComUSB scu;
private Map registeredUsbDevices = new LinkedHashMap<>();
private List listeners = new LinkedList<>();
final Object lock = new Object();
private final ScheduledExecutorService serialDeviceWorker = Executors.newScheduledThreadPool(1);
public HotPlugEventWatcher() {
LOGGER.info("Create new instance of SerialComUSB.");
try {
scu = new SerialComUSB(null, null);
}
catch (Exception ex) {
LOGGER.warn("Create new instance of SerialComManager failed.", ex);
throw new RuntimeException("Create new instance of SerialComManager failed.", ex);
}
catch (Error err) {
LOGGER.warn("Create new instance of SerialComManager failed.", err);
throw new RuntimeException("Create new instance of SerialComManager failed.", err);
}
}
public void addEventListener(HotPlugEventListener listener) {
listeners.add(listener);
}
public void removeEventListener(HotPlugEventListener listener) {
listeners.remove(listener);
}
@Override
public void onUSBHotPlugEvent(int event, int USBVID, int USBPID, String serialNumber) {
LOGGER.info("Received hotplug event: {}, USBVID: {}, USBPID: {}, serialNumber: {}", event,
ByteUtils.intToHex(USBVID), ByteUtils.intToHex(USBPID), serialNumber);
if (event == SerialComUSB.DEV_ADDED) {
LOGGER.info("USB device was added.");
}
else if (event == SerialComUSB.DEV_REMOVED) {
LOGGER.info("USB device was removed.");
}
// TODO change this to not use SwingUtilities ... but must be executed in separate thread
SwingUtilities.invokeLater(new Runnable() {
public void run() {
listConnectedDevices();
}
});
}
private void listConnectedDevices() {
LOGGER.info("List connected USB devices.");
try {
// String tempDir = System.getProperty("java.io.tmpdir");
// File temp = new File(tempDir, "jbidibc");
// temp.mkdirs();
// SerialComManager scm = new SerialComManager("scm", temp.getAbsolutePath(), true, false);
// SerialComUSB scu = new SerialComUSB(null, null);
// SerialComManager scm = new SerialComManager();
SerialComUSBdevice[] usbDevices = null;
try {
usbDevices = scu.listUSBdevicesWithInfo(SerialComUSB.V_ALL);
}
catch (SerialComException ex) {
LOGGER.info("List devices failed. Try again after a second.");
Thread.sleep(1000);
usbDevices = scu.listUSBdevicesWithInfo(SerialComUSB.V_ALL);
}
updateRegisteredUsbDevice(usbDevices);
}
catch (Exception e) {
LOGGER.warn("List USB devices failed.", e);
}
catch (Error err) {
LOGGER.warn("Create SerialComManager and list USB devices failed.", err);
}
}
private void updateRegisteredUsbDevice(SerialComUSBdevice[] usbDevices) {
LOGGER.info("Update the registered USB devices.");
// keep the currently registered devices
Map tempDevices = new LinkedHashMap<>();
tempDevices.putAll(registeredUsbDevices);
for (int x = 0; x < usbDevices.length; x++) {
final SerialComUSBdevice scmUsbDevice = usbDevices[x];
StringBuilder keyBuilder = new StringBuilder();
keyBuilder
.append(scmUsbDevice.getVendorID()).append(":").append(scmUsbDevice.getProductID()).append(":")
.append(scmUsbDevice.getSerialNumber());
final String key = keyBuilder.toString();
UsbDevice device = registeredUsbDevices.get(key);
if (device == null) {
final String deviceInfo =
ToStringBuilder.reflectionToString(scmUsbDevice, ToStringStyle.SHORT_PREFIX_STYLE);
LOGGER.info("Register new device: {}", deviceInfo);
UsbDevice usbDevice = new UsbDevice(scmUsbDevice);
registeredUsbDevices.put(key, usbDevice);
boolean isSerialDevice = false;
String[] comPorts = findSerialDeviceComPorts(scmUsbDevice, deviceInfo);
if (comPorts == null || comPorts.length == 0) {
LOGGER.info("Current usbDevice is not a serial device (no COM port assigned): {}", deviceInfo);
// schedule task to check again for serial port after 5 seconds
serialDeviceWorker.schedule(new Runnable() {
@Override
public void run() {
String[] comPorts = findSerialDeviceComPorts(scmUsbDevice, deviceInfo);
if (comPorts != null && comPorts.length > 0) {
LOGGER.info("The current device has COM ports: {}", new Object[] { comPorts });
UsbDevice usbDevice = registeredUsbDevices.get(key);
if (usbDevice != null) {
usbDevice.setComPorts(comPorts);
LOGGER.info("Found registered USB device to notify: {}", usbDevice);
notifyListeners(SerialComUSB.DEV_ADDED, usbDevice);
}
else {
LOGGER.info("Registered USB device not found: {}", usbDevice);
}
}
else {
LOGGER.info("Current usbDevice is not a serial device (no COM port assigned): {}",
deviceInfo);
}
}
}, 5, TimeUnit.SECONDS);
}
else {
isSerialDevice = true;
LOGGER.info("The current device has COM ports: {}", new Object[] { comPorts });
usbDevice.setComPorts(comPorts);
}
if (isSerialDevice) {
notifyListeners(SerialComUSB.DEV_ADDED, usbDevice);
}
}
else {
// the current device was registered already, remove from temp map
tempDevices.remove(key);
}
}
if (MapUtils.isNotEmpty(tempDevices)) {
// remove devices from map
for (Entry entry : tempDevices.entrySet()) {
LOGGER.info("The current device was removed, key: {}, device: {}", entry.getKey(),
ToStringBuilder.reflectionToString(entry.getValue(), ToStringStyle.SHORT_PREFIX_STYLE));
UsbDevice usbDevice = registeredUsbDevices.remove(entry.getKey());
if (usbDevice != null && usbDevice.getComPorts() != null) {
notifyListeners(SerialComUSB.DEV_REMOVED, usbDevice);
}
}
}
}
private String[] findSerialDeviceComPorts(final SerialComUSBdevice scmUsbDevice, final String deviceInfo) {
String[] comPorts = null;
try {
// SerialComUSB scu = new SerialComUSB(null, null);
comPorts =
scu.findComPortFromUSBAttributes(scmUsbDevice.getVendorID(), scmUsbDevice.getProductID(),
scmUsbDevice.getSerialNumber());
}
catch (SerialComException ex) {
LOGGER.warn("Find COM ports for usbDevice failed: {}", deviceInfo, ex);
}
return comPorts;
}
private void notifyListeners(int event, UsbDevice usbDevice) {
for (HotPlugEventListener listener : listeners) {
switch (event) {
case SerialComUSB.DEV_ADDED:
listener.usbDeviceAdded(usbDevice);
break;
case SerialComUSB.DEV_REMOVED:
listener.usbDeviceRemoved(usbDevice);
break;
default:
break;
}
}
}
@Override
public void run() {
// int PRODUCT_VID = 0x0403;
// int PRODUCT_PID = 0x6001;
int PRODUCT_VID = SerialComUSB.DEV_ANY;
int PRODUCT_PID = SerialComUSB.DEV_ANY;
int handle = -1;
try {
LOGGER.info("Try to register USBHotPlugEventListener.");
handle = scu.registerUSBHotPlugEventListener(this, PRODUCT_VID, PRODUCT_PID, null);
listConnectedDevices();
LOGGER.info("Registered USBHotPlugEventListener, handle: {}", handle);
synchronized (lock) {
lock.wait();
}
LOGGER.info("Wait for termination passed.");
}
catch (Exception ex) {
LOGGER.warn("Register USBHotPlugEventListener failed.", ex);
}
catch (Error ex) {
LOGGER.warn("Register USBHotPlugEventListener failed.", ex);
}
finally {
if (handle > -1) {
try {
scu.unregisterUSBHotPlugEventListener(handle);
}
catch (Exception ex1) {
LOGGER.warn("Unregister USBHotPlugEventListener failed.", ex1);
}
handle = -1;
}
}
LOGGER.info("The watcher has terminated.");
}
public void stop() {
LOGGER.info("Stop the watcher.");
try {
synchronized (lock) {
lock.notify();
}
}
catch (Exception ex) {
LOGGER.warn("Notify lock to shutdown USB hotplug event listener failed.", ex);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy