Detecting a doi collision
-
hi,
when the bacnet4j app monitors other bacnet devices (notifications and cov) then detecting a doi collision gets important.
when two davices do have the same doi then one device will miss event data.the iamrequest.java has to be modified as follows:
/** * see if the address is my own local echo * * @param from * @return */ private boolean localEcho(Address from, Address[] localAddresses) { for ( Address addr : localAddresses) { boolean equal = addr.equals(from); if (equal) { return true; } } return false; } // modified @Override public void handle(LocalDevice localDevice, Address from, Network network) { // Make sure we're not hearing from ourselves. int myDoi = localDevice.getConfiguration().getInstanceId(); int remoteDoi = iAmDeviceIdentifier.getInstanceNumber(); if (remoteDoi == myDoi) { // get my bacnet address and compare the addresses Address[] myAddresses = localDevice.getAllLocalAddresses(); boolean lEcho = localEcho(from, myAddresses); if ( lEcho) { return; } else { System.out.println("another instance with my doi found!"); } } // Register the device in the list of known devices. RemoteDevice d = localDevice.getRemoteDeviceCreate(remoteDoi, from, network); d.setMaxAPDULengthAccepted(maxAPDULengthAccepted.intValue()); d.setSegmentationSupported(segmentationSupported); d.setVendorId(vendorId.intValue()); // Fire the appropriate event. localDevice.getEventHandler().fireIAmReceived(d); }
in localdevice.java is the function getLocalIPAdress, but we have multihomed linux boxes - a pain for java developers :wink:
so we need to add a new function:public Address[] getAllLocalAddresses() { try { ArrayList<Address> lAddr = new ArrayList<Address>(); for (NetworkInterface iface : Collections.list(NetworkInterface.getNetworkInterfaces())) { for (InetAddress addr : Collections.list(iface.getInetAddresses())) { if (!addr.isLoopbackAddress() && addr.isSiteLocalAddress()) { byte[] addrBytes = addr.getAddress(); Address address = new Address(addrBytes, messageControl.getPort()); lAddr.add(address); } } } int elems = lAddr.size(); Address[] retVal = new Address[elems]; lAddr.toArray(retVal); return retVal; } catch (Exception e) { // Should never happen, so just wrap in a RuntimeException throw new RuntimeException(e); } }
now you can easily detect if there is another device wioth the same doi:
public boolean isUniqueInstanceNumber() { int deviceID = getConfiguration().getInstanceId(); RemoteDevice rd = getRemoteDevice(deviceID); if (null != rd) { return false; } else { return true; } }
some functionality which is needed in our daily work.
robert
-
Thanks Robert. This is been added in similar form to the code base. It imposed a difference to the public interface in LocalDevice though, in that the getAddress method now take an InetAddress parameter. The equivalent code is now:
d.getAddress(d.getDefaultLocalInetAddress())
All code changes have been checked into CVS.