calimero-project / calimero-core

Core library for KNX network access and management
Other
129 stars 65 forks source link

USB device autodetecting login detects right but opens the wrong device #29

Closed alesf76 closed 8 years ago

alesf76 commented 8 years ago

When it scans for an USB device, if there are more than one HID devices, it detects correctly which is the KNX interface, but then opens the wrong one, in this examples the KNX interface is device 002, it detects it, but then it tries to open device 003 which has already been identified has the wrong one. (note: tested on windows)

C:\driver\calimero_server_jar>java -jar calimero-server.jar server-config.xml [main] INFO calimero.server - Discovery service network interfaces: [main] INFO calimero.server - listen on eth3 [main] INFO calimero.server - outgoing eth3 [main] INFO calimero.server - Service container : [main] INFO calimero.server - IPv4 UDP host 192.168.1.102 port 3671 routing false [main] INFO calimero.server - usb connection, TP1 medium, device 1.1.249 [main] INFO calimero.server - GrpAddrFilter [] [main] INFO calimero.server - connect to [main] INFO calimero.usb - Found KNX devices: |--Bus 001 Device 002: ID 147b:5120 [main] INFO calimero.usb. - Bus 001 Device 003: ID 0424:2514 [main] WARN calimero.usb. - Interface doesn't look right, no HID class [main] WARN calimero.usb. - Interface doesn't look right, no HID class [main] ERROR calimero.link - initial connection attempt tuwien.auto.calimero.KNXException: open USB connection at tuwien.auto.calimero.serial.usb.UsbConnection.(UsbConnection.ja va:411) at tuwien.auto.calimero.serial.usb.UsbConnection.(UsbConnection.ja va:380) at tuwien.auto.calimero.link.KNXNetworkLinkUsb.(KNXNetworkLinkUsb. java:106) at tuwien.auto.calimero.server.gateway.SubnetConnector.lambda$openNetwor kLink$10(SubnetConnector.java:225) at tuwien.auto.calimero.link.Connector$Link.connect(Connector.java:446) at tuwien.auto.calimero.link.Connector$Link.(Connector.java:219) at tuwien.auto.calimero.link.Connector$Link.(Connector.java:176) at tuwien.auto.calimero.link.Connector.newLink(Connector.java:157) at tuwien.auto.calimero.server.gateway.SubnetConnector.openNetworkLink(S ubnetConnector.java:265) at tuwien.auto.calimero.server.Launcher.connect(Launcher.java:525) at tuwien.auto.calimero.server.Launcher.run(Launcher.java:455) at tuwien.auto.calimero.server.Launcher.main(Launcher.java:398) Caused by: javax.usb.UsbPlatformException: USB error 12: Can't open device Bus 0 01 Device 003: ID 0424:2514: Operation not supported or unimplemented on this pl atform

bmalinowsky commented 8 years ago

Detecting and opening a device are unrelated. Detection only makes sure that all devices -- known to calimero and where it thinks its a knx interface -- are shown to the user.

0424:2514 is the smc usb hub, so this does not match, nor will a product:vendor lookup select it. It would only apply if you use a very general pattern matching in the server-config, like "usb" or so.

How do you specify your ABB interface in the config? Do you use product:vendor, i.e., do you write something like <knxSubnet type="usb">147b:5120</knxSubnet> or do you use a name, e.g., <knxSubnet type="usb">abb</knxSubnet>?

alesf76 commented 8 years ago

I was thinking that leaving void the usb name i.e. would have triggered an autodetection, but I was wrong. I made a little "brute" modification to enable this funcionality: if no usb device is choosen, the first knx interface is used. Sorry but I don' t know how to use git :(

    private static boolean isKNXIntfID(final String device) {
    try {
        final String[] split = device.split(":");
        final int vend=Integer.parseInt(split[0],16),prod=Integer.parseInt(split[1],16);
        return (ArrayUtils.contains(vendorIds,vend) && ArrayUtils.contains(productIds,prod));
    }
    catch (Exception e) {
        return false;
    }
}

// Cross-platform way to do name lookup for USB devices, using the low-level API.
// Parse the USB device string descriptions for name, extract the vendor:product ID
// string. Pass that ID to findDevice. which will do the lookup by ID.
private static UsbDevice findDeviceByNameLowLevel(final String name) throws KNXException
{
    final List<String> list = getDeviceDescriptionsLowLevel();
    list.removeIf(i -> i.toLowerCase().indexOf(name.toLowerCase()) == -1);
    if (list.size()>1) {
        list.removeIf(i -> !isKNXIntfID(i.substring(i.indexOf("ID") + 3, i.indexOf("\n"))));
    }

    if (list.isEmpty())
        throw new KNXException("no USB device found by name " + name);
    final String desc = list.get(0);
    final String id = desc.substring(desc.indexOf("ID") + 3, desc.indexOf("\n"));
    return findDevice(id);
}

I also added some missing interface ids

private static final int[] vendorIds = {
    0x135e, // Insta: also used in Hager, Jung, Merten, Berker, Gira
    0x0e77, // Siemens: also used in Weinzierl, Merlin, Hensel
    0x145c, // Busch-Jaeger
    0x147b, // ABB stotz-kontakt
    0x16D0, // Tapko and others
    0x0681, // Siemens OCI700 interface (Synco family),
};

private static final int[] productIds = {
    // uses Insta
    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026,
    // uses Siemens
    0x0102, 0x0104, 0x0111, 0x0112, 0x0121, 0x0141, 0x2001,
    // uses BJ
    0x1330, // BJ flush-mounted
    0x1490, // BJ surface-mounted
    // uses ABB
    0x5120,
    // uses Tapko
    0x0490, 0x0491, 0x0492,
    // uses OCI
    0x0014,
};
bmalinowsky commented 8 years ago

Thanks, also for the new IDs! As fallback if no device name is given, I modified the behavior to specifically check for an empty name. Otherwise, it would not work for lab equipment or DIY adapters that are not listed. Also, for reducing a list of > 1 KNX interfaces to 1, the overall approach currently used by the usb connection is not sufficient, although enough for most users. The reason is that device selection is not unique and does not distinguish 2 same devices. One would have to use, e.g., the unique but awkward bus/device notation.