Skip to content

Commit

Permalink
[5153] Discovery for USB devices with serial port (eclipse-archived#5315
Browse files Browse the repository at this point in the history
)

This commit contains an API for a generic discovery for USB devices that can be accessed via a serial port (typically provided by an operating system-specific driver). Examples of such things that could be discovered are bridges for wireless protocols (like, e.g., Zigbee, Z-Wave, HomeMatic, or HomeMatic IP) using an USB dongle, where the binding uses serial communication to communicate with the dongle.

This discovery needs to be complemented from two sides: On the one side, bindings must contribute 'DiscoveryParticipants', which, given information about serial port and USB device provided by the discovery, generate a DiscoveryResult in case they support the USB device. On the other side, an implementation of the actual scanning for USB devices and serial ports must be provided. There are different options for providing such a discovery, as discussed on eclipse-archived#5153.

This commit contains an implementation of the actual discovery that can be used on Linux systems, which regularly scans the so-called 'sysfs', a Linux pseudo file system that provides information about devices.

fixes eclipse-archived#5153
Signed-off-by: Henning Sudbrock <[email protected]>
  • Loading branch information
hsudbrock authored and Florian Stolte committed Apr 11, 2018
1 parent e213367 commit 332f540
Show file tree
Hide file tree
Showing 47 changed files with 2,520 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src/test/java"/>
<classpathentry kind="output" path="target/test-classes"/>
</classpath>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs.test</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Eclipse SmartHome Configuration Discovery USB-Serial Linux Sysfs Tests
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-SymbolicName: org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs.test;singleton:=true
Bundle-Vendor: Eclipse.org/SmartHome
Bundle-Version: 0.10.0.qualifier
Fragment-Host: org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs
Import-Package:
org.eclipse.jdt.annotation;resolution:=optional,
org.eclipse.smarthome.config.discovery.usbserial.testutil,
org.eclipse.smarthome.test.java,
org.hamcrest;core=split,
org.hamcrest.collection,
org.hamcrest.core,
org.junit;version="4.0.0",
org.junit.rules,
org.mockito,
org.mockito.invocation,
org.mockito.stubbing,
org.mockito.verification
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
This content is produced and maintained by the Eclipse SmartHome project.

* Project home: https://eclipse.org/smarthome/

== Declared Project Licenses

This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.

== Source Code

https://github.com/eclipse/smarthome

== Copyright Holders

See the NOTICE file distributed with the source code at
https://github.com/eclipse/smarthome/blob/master/NOTICE
for detailed information regarding copyright ownership.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source.. = src/test/java/
output.. = target/test-classes/
bin.includes = META-INF/,\
.,\
NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig">
<booleanAttribute key="append.args" value="true"/>
<stringAttribute key="application" value="org.eclipse.pde.junit.runtime.coretestapplication"/>
<booleanAttribute key="askclear" value="false"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="true"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="true"/>
<booleanAttribute key="clearws" value="true"/>
<booleanAttribute key="clearwslog" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
<booleanAttribute key="default" value="false"/>
<booleanAttribute key="default_auto_start" value="true"/>
<booleanAttribute key="includeOptional" value="false"/>
<stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs.test"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs.test"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JRE for JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs.test"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.equinox.p2.director.app.product"/>
<booleanAttribute key="run_in_ui_thread" value="false"/>
<stringAttribute key="selected_target_plugins" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,ch.qos.logback.slf4j@default:false,com.eclipsesource.jaxrs.jersey-min@default:default,com.google.gson*2.7.0.v20170129-0911@default:default,com.google.guava@default:default,com.google.inject@default:default,com.ibm.icu.base@default:default,com.ibm.icu@default:default,javax.annotation@default:default,javax.inject@default:default,javax.measure.unit-api@default:default,javax.transaction@default:false,javax.xml@default:default,net.bytebuddy.byte-buddy-agent@default:default,net.bytebuddy.byte-buddy@default:default,org.antlr.runtime@default:default,org.apache.ant@default:default,org.apache.batik.css@default:default,org.apache.batik.util@default:default,org.apache.commons.collections@default:default,org.apache.commons.io@default:default,org.apache.commons.lang@default:default,org.apache.commons.logging@default:default,org.apache.felix.scr@default:default,org.codehaus.groovy@default:default,org.eclipse.compare.core@default:default,org.eclipse.core.commands@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.databinding.observable@default:default,org.eclipse.core.databinding.property@default:default,org.eclipse.core.databinding@default:default,org.eclipse.core.expressions@default:default,org.eclipse.core.filesystem@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.resources@default:default,org.eclipse.core.runtime@default:true,org.eclipse.emf.common@default:default,org.eclipse.emf.ecore.change@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:true,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.util@default:default,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.help@default:default,org.eclipse.jface.databinding@default:default,org.eclipse.jface@default:default,org.eclipse.osgi.compatibility.state@default:false,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.eclipse.swt@default:default,org.eclipse.team.core@default:default,org.eclipse.xtend.lib.macro@default:default,org.eclipse.xtend.lib@default:default,org.eclipse.xtext.common.types@default:default,org.eclipse.xtext.smap@default:default,org.eclipse.xtext.util@default:default,org.eclipse.xtext.xbase.lib@default:default,org.eclipse.xtext.xbase@default:default,org.eclipse.xtext@default:default,org.hamcrest.core@default:default,org.hamcrest.integration@default:default,org.hamcrest.library@default:default,org.hamcrest.text@default:default,org.hamcrest@default:default,org.junit@default:default,org.mockito.mockito-core@default:default,org.objectweb.asm@default:default,org.objenesis@default:default,org.slf4j.api@default:default,org.slf4j.jcl@default:default,org.slf4j.log4j@default:default,org.w3c.css.sac@default:default,tec.uom.lib.uom-lib-common@default:default,tec.uom.se@default:default"/>
<stringAttribute key="selected_workspace_plugins" value="org.eclipse.smarthome.config.core@default:default,org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs.test@default:false,org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs@default:default,org.eclipse.smarthome.config.discovery.usbserial.test@default:default,org.eclipse.smarthome.config.discovery.usbserial@default:default,org.eclipse.smarthome.config.discovery@default:true,org.eclipse.smarthome.config.xml@default:default,org.eclipse.smarthome.core.autoupdate@default:default,org.eclipse.smarthome.core.persistence@default:default,org.eclipse.smarthome.core.scheduler@default:default,org.eclipse.smarthome.core.thing.xml@default:default,org.eclipse.smarthome.core.thing@default:true,org.eclipse.smarthome.core@default:true,org.eclipse.smarthome.io.console@default:default,org.eclipse.smarthome.model.core@default:default,org.eclipse.smarthome.model.item@default:default,org.eclipse.smarthome.model.persistence@default:default,org.eclipse.smarthome.test@default:default"/>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfig" value="true"/>
<booleanAttribute key="useDefaultConfigArea" value="false"/>
<booleanAttribute key="useProduct" value="false"/>
</launchConfiguration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>config</artifactId>
<groupId>org.eclipse.smarthome.bundles</groupId>
<version>0.10.0-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.smarthome.config</groupId>
<artifactId>org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs.test</artifactId>
<packaging>eclipse-test-plugin</packaging>
<name>Eclipse SmartHome Configuration USB-Serial Discovery for Linux using sysfs scanning Tests</name>

<properties>
<bundle.symbolicName>org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs.test</bundle.symbolicName>
<bundle.namespace>org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs.test</bundle.namespace>
</properties>

<build>
<plugins>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>target-platform-configuration</artifactId>
<configuration>
<environments combine.self="override"></environments>
<dependency-resolution>
<extraRequirements>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.ds</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.equinox.event</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.core</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.core.thing</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.smarthome.core.thing.xml</id>
<versionRange>0.0.0</versionRange>
</requirement>
</extraRequirements>
</dependency-resolution>
</configuration>
</plugin>
<plugin>
<groupId>${tycho-groupid}</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<configuration>
<bundleStartLevel>
<bundle>
<id>org.eclipse.equinox.ds</id>
<level>1</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.equinox.event</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core.thing</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.core.thing.xml</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
<bundle>
<id>org.eclipse.smarthome.config.core</id>
<level>4</level>
<autoStart>true</autoStart>
</bundle>
</bundleStartLevel>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* Copyright (c) 2014,2018 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs.internal;

import static java.util.Arrays.asList;
import static java.util.Collections.emptySet;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.collection.IsEmptyCollection.empty;
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;

import java.io.IOException;
import java.util.HashSet;

import org.eclipse.smarthome.config.discovery.usbserial.UsbSerialDeviceInformation;
import org.eclipse.smarthome.config.discovery.usbserial.linuxsysfs.internal.DeltaUsbSerialScanner.Delta;
import org.eclipse.smarthome.config.discovery.usbserial.testutil.UsbSerialDeviceInformationGenerator;
import org.junit.Before;
import org.junit.Test;

/**
* Unit tests for the {@link DeltaUsbSerialScanner}.
*
* @author Henning Sudbrock - initial contribution
*/
public class DeltaUsbSerialScannerTest {

UsbSerialDeviceInformationGenerator usbDeviceInfoGenerator = new UsbSerialDeviceInformationGenerator();

private UsbSerialScanner usbSerialScanner;
private DeltaUsbSerialScanner deltaUsbSerialScanner;

@Before
public void setup() {
usbSerialScanner = mock(UsbSerialScanner.class);
deltaUsbSerialScanner = new DeltaUsbSerialScanner(usbSerialScanner);
}

/**
* If there are no devices discovered in a first scan, then there is no delta.
*/
@Test
public void testInitialEmptyResult() throws IOException {
when(usbSerialScanner.scan()).thenReturn(emptySet());

Delta<UsbSerialDeviceInformation> delta = deltaUsbSerialScanner.scan();

assertThat(delta.getAdded(), is(empty()));
assertThat(delta.getRemoved(), is(empty()));
assertThat(delta.getUnchanged(), is(empty()));
}

/**
* If there are devices discovered in a first scan, then all devices are in the 'added' section of the delta.
*/
@Test
public void testInitialNonEmptyResult() throws IOException {
UsbSerialDeviceInformation usb1 = usbDeviceInfoGenerator.generate();
UsbSerialDeviceInformation usb2 = usbDeviceInfoGenerator.generate();
when(usbSerialScanner.scan()).thenReturn(new HashSet<>(asList(usb1, usb2)));

Delta<UsbSerialDeviceInformation> delta = deltaUsbSerialScanner.scan();

assertThat(delta.getAdded(), containsInAnyOrder(usb1, usb2));
assertThat(delta.getRemoved(), is(empty()));
assertThat(delta.getUnchanged(), is(empty()));
}

/**
* If a first scan discovers devices usb1 and usb2, and a second scan discovers devices usb2 and usb3, then the
* delta for the second scan is: usb3 is added, usb1 is removed, and usb2 is unchanged.
*/
@Test
public void testDevicesAddedAndRemovedAndUnchanged() throws IOException {
UsbSerialDeviceInformation usb1 = usbDeviceInfoGenerator.generate();
UsbSerialDeviceInformation usb2 = usbDeviceInfoGenerator.generate();
UsbSerialDeviceInformation usb3 = usbDeviceInfoGenerator.generate();

when(usbSerialScanner.scan()).thenReturn(new HashSet<>(asList(usb1, usb2)));
deltaUsbSerialScanner.scan();

when(usbSerialScanner.scan()).thenReturn(new HashSet<>(asList(usb2, usb3)));
Delta<UsbSerialDeviceInformation> delta = deltaUsbSerialScanner.scan();

assertThat(delta.getAdded(), contains(usb3));
assertThat(delta.getRemoved(), contains(usb1));
assertThat(delta.getUnchanged(), contains(usb2));
}

}
Loading

0 comments on commit 332f540

Please sign in to comment.