diff --git a/src/net/ash/HIDToVPADNetworkClient/controller/DS4NewController.java b/src/net/ash/HIDToVPADNetworkClient/controller/DS4NewController.java index 3c657da..22b1f8c 100644 --- a/src/net/ash/HIDToVPADNetworkClient/controller/DS4NewController.java +++ b/src/net/ash/HIDToVPADNetworkClient/controller/DS4NewController.java @@ -1,6 +1,9 @@ package net.ash.HIDToVPADNetworkClient.controller; +import java.util.Arrays; + import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException; +import net.ash.HIDToVPADNetworkClient.util.Settings; public class DS4NewController extends PureJavaHidController { public static final short DS4_NEW_CONTROLLER_VID = 0x54C; @@ -8,12 +11,19 @@ public class DS4NewController extends PureJavaHidController { public DS4NewController(String identifier) throws ControllerInitializationFailedException { super(identifier); - // truncate package to 6; - this.PACKET_LENGTH = 6; + if (Settings.isMacOSX()) { + this.PACKET_LENGTH = 7; + } else { + this.PACKET_LENGTH = 6; + } } @Override public byte[] pollLatestData() { + if (Settings.isMacOSX()) { // for some reason the controller has one extra byte at the beginning under OSX + return Arrays.copyOfRange(currentData, 1, 7); + } + return currentData.clone(); } diff --git a/src/net/ash/HIDToVPADNetworkClient/controller/PureJavaHidController.java b/src/net/ash/HIDToVPADNetworkClient/controller/PureJavaHidController.java index 6dd8f74..57c2523 100644 --- a/src/net/ash/HIDToVPADNetworkClient/controller/PureJavaHidController.java +++ b/src/net/ash/HIDToVPADNetworkClient/controller/PureJavaHidController.java @@ -28,11 +28,13 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; import lombok.Synchronized; +import lombok.extern.java.Log; import net.ash.HIDToVPADNetworkClient.exeption.ControllerInitializationFailedException; import net.ash.HIDToVPADNetworkClient.util.PureJavaHidApiManager; import purejavahidapi.HidDevice; import purejavahidapi.InputReportListener; +@Log public class PureJavaHidController extends Controller implements InputReportListener { private final Object dataLock = new Object(); protected byte[] currentData = new byte[1]; @@ -43,12 +45,20 @@ public class PureJavaHidController extends Controller implements InputReportList public static Controller getInstance(String deviceIdentifier) throws IOException, ControllerInitializationFailedException { HidDevice device = PureJavaHidApiManager.getDeviceByPath(deviceIdentifier); + + short vid = 0; + short pid = 0; + if (device != null) { + vid = device.getHidDeviceInfo().getVendorId(); + pid = device.getHidDeviceInfo().getProductId(); + device.close(); + } + // We use a special version to optimize the data for the switch pro controller - if (device.getHidDeviceInfo().getVendorId() == SwitchProController.SWITCH_PRO_CONTROLLER_VID - && device.getHidDeviceInfo().getProductId() == SwitchProController.SWITCH_PRO_CONTROLLER_PID) { + if (vid == SwitchProController.SWITCH_PRO_CONTROLLER_VID && pid == SwitchProController.SWITCH_PRO_CONTROLLER_PID) { + return new SwitchProController(deviceIdentifier); - } else if (device.getHidDeviceInfo().getVendorId() == DS4NewController.DS4_NEW_CONTROLLER_VID - && device.getHidDeviceInfo().getProductId() == DS4NewController.DS4_NEW_CONTROLLER_PID) { + } else if (vid == DS4NewController.DS4_NEW_CONTROLLER_VID && pid == DS4NewController.DS4_NEW_CONTROLLER_PID) { return new DS4NewController(deviceIdentifier); } else { return new PureJavaHidController(deviceIdentifier); @@ -64,6 +74,9 @@ public class PureJavaHidController extends Controller implements InputReportList HidDevice device; try { device = PureJavaHidApiManager.getDeviceByPath(identifier); + if (device == null) { + return false; + } device.setInputReportListener(this); setHidDevice(device); @@ -83,7 +96,16 @@ public class PureJavaHidController extends Controller implements InputReportList @Override public void destroyDriver() { - getHidDevice().close(); + try { + getHidDevice().close(); + } catch (IllegalStateException e) { + if (e.getMessage().equals("device not open")) { + log.info("Error closing the device." + e.getMessage()); + } else { + throw e; + } + } + } @Override diff --git a/src/net/ash/HIDToVPADNetworkClient/controller/SwitchProController.java b/src/net/ash/HIDToVPADNetworkClient/controller/SwitchProController.java index 3ed078c..d1a6842 100644 --- a/src/net/ash/HIDToVPADNetworkClient/controller/SwitchProController.java +++ b/src/net/ash/HIDToVPADNetworkClient/controller/SwitchProController.java @@ -35,7 +35,7 @@ public class SwitchProController extends PureJavaHidController { @Override public byte[] pollLatestData() { - if(currentData == null || currentData.length < 10){ + if (currentData == null || currentData.length < 10) { return new byte[0]; } // remove unused data (because only changed data will be sent) diff --git a/src/net/ash/HIDToVPADNetworkClient/controller/XInputController.java b/src/net/ash/HIDToVPADNetworkClient/controller/XInputController.java index 4294597..ba970d2 100644 --- a/src/net/ash/HIDToVPADNetworkClient/controller/XInputController.java +++ b/src/net/ash/HIDToVPADNetworkClient/controller/XInputController.java @@ -55,7 +55,7 @@ public class XInputController extends Controller { try { device = XInputDevice.getDeviceFor(pad); } catch (XInputNotLoadedException e) { - e.printStackTrace(); + e.printStackTrace(); } if (device == null) return false; setDevice(device); @@ -65,9 +65,9 @@ public class XInputController extends Controller { @Override public byte[] pollLatestData() { boolean newData = false; - try{ + try { newData = device.poll(); - }catch(BufferUnderflowException e){ + } catch (BufferUnderflowException e) { log.info("Error reading the XInput data " + e.getMessage()); setActive(false); Thread.currentThread().stop(); diff --git a/src/net/ash/HIDToVPADNetworkClient/gui/GuiInputControls.java b/src/net/ash/HIDToVPADNetworkClient/gui/GuiInputControls.java index 2608830..e8b2067 100644 --- a/src/net/ash/HIDToVPADNetworkClient/gui/GuiInputControls.java +++ b/src/net/ash/HIDToVPADNetworkClient/gui/GuiInputControls.java @@ -38,10 +38,11 @@ import javax.swing.SwingUtilities; import javax.swing.Timer; import lombok.Getter; +import net.ash.HIDToVPADNetworkClient.manager.ControllerManager; import net.ash.HIDToVPADNetworkClient.network.NetworkManager; import net.ash.HIDToVPADNetworkClient.util.Settings; -public final class GuiInputControls extends JPanel implements ActionListener { +public final class GuiInputControls extends JPanel { private static final long serialVersionUID = 1L; @Getter private static GuiInputControls instance = new GuiInputControls(); @@ -59,6 +60,41 @@ public final class GuiInputControls extends JPanel implements ActionListener { final JButton connectButton = new JButton(CONNECT); connectButton.setAlignmentX(Component.CENTER_ALIGNMENT); + final JCheckBox cbautoScanForController = new JCheckBox(); + if (Settings.isMacOSX()) { + cbautoScanForController.setEnabled(false); + } else { + cbautoScanForController.setSelected(Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS); + } + + cbautoScanForController.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + boolean selected = ((JCheckBox) e.getSource()).isSelected(); + Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS = selected; + cbautoScanForController.setSelected(selected); + } + }); + + final JButton scanButton = new JButton("Scan for Controllers"); + scanButton.setAlignmentX(Component.CENTER_ALIGNMENT); + scanButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + ControllerManager.detectControllers(); + } + }); + } + }); + + JPanel scanWrap = new JPanel(); + scanWrap.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); + scanWrap.add(new JLabel("Auto Scan for Controllers: ")); + scanWrap.add(cbautoScanForController); + ipTextBox = new JTextField(); ipTextBox.setColumns(15); ipTextBox.setText(Settings.getIpAddr()); @@ -67,9 +103,6 @@ public final class GuiInputControls extends JPanel implements ActionListener { ipTextBoxWrap.add(ipTextBox); ipTextBoxWrap.setMaximumSize(new Dimension(1000, 20)); - JLabel statusLabel = new JLabel("Ready."); - statusLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - final JCheckBox cbautoActivateController = new JCheckBox(); cbautoActivateController.setSelected(Settings.AUTO_ACTIVATE_CONTROLLER); cbautoActivateController.addActionListener(new ActionListener() { @@ -93,14 +126,33 @@ public final class GuiInputControls extends JPanel implements ActionListener { add(Box.createRigidArea(new Dimension(1, 4))); add(connectButton); - add(Box.createRigidArea(new Dimension(1, 8))); - - add(statusLabel); + add(Box.createRigidArea(new Dimension(1, 4))); + add(scanButton); + add(scanWrap); + add(Box.createVerticalGlue()); add(autoActivateWrap); add(Box.createVerticalGlue()); - connectButton.addActionListener(this); + connectButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + Settings.setIpAddr(ipTextBox.getText()); + if (NetworkManager.getInstance().isReconnecting()) { + + } else { + if (NetworkManager.getInstance().isConnected()) { + NetworkManager.getInstance().disconnect(); + } else { + NetworkManager.getInstance().connect(ipTextBox.getText()); + } + } + } + }); + } + }); int delay = 100; // milliseconds ActionListener taskPerformer = new ActionListener() { @@ -119,23 +171,4 @@ public final class GuiInputControls extends JPanel implements ActionListener { }; new Timer(delay, taskPerformer).start(); } - - @Override - public void actionPerformed(ActionEvent e) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - Settings.setIpAddr(ipTextBox.getText()); - if (NetworkManager.getInstance().isReconnecting()) { - - } else { - if (NetworkManager.getInstance().isConnected()) { - NetworkManager.getInstance().disconnect(); - } else { - NetworkManager.getInstance().connect(ipTextBox.getText()); - } - } - } - }); - - } } diff --git a/src/net/ash/HIDToVPADNetworkClient/gui/GuiMain.java b/src/net/ash/HIDToVPADNetworkClient/gui/GuiMain.java index 126a3a2..bc5f5ee 100644 --- a/src/net/ash/HIDToVPADNetworkClient/gui/GuiMain.java +++ b/src/net/ash/HIDToVPADNetworkClient/gui/GuiMain.java @@ -58,7 +58,7 @@ public class GuiMain extends JPanel implements MessageBoxListener { super(new BorderLayout()); GuiControllerList leftControllerList = new GuiControllerList(); - leftControllerList.setPreferredSize(new Dimension(300, 100)); + leftControllerList.setPreferredSize(new Dimension(400, 200)); add(leftControllerList, BorderLayout.CENTER); GuiInputControls rightSideControls = GuiInputControls.getInstance(); add(rightSideControls, BorderLayout.LINE_END); diff --git a/src/net/ash/HIDToVPADNetworkClient/manager/ActiveControllerManager.java b/src/net/ash/HIDToVPADNetworkClient/manager/ActiveControllerManager.java index 8dc173f..85acf31 100644 --- a/src/net/ash/HIDToVPADNetworkClient/manager/ActiveControllerManager.java +++ b/src/net/ash/HIDToVPADNetworkClient/manager/ActiveControllerManager.java @@ -51,9 +51,13 @@ public final class ActiveControllerManager implements Runnable { new Thread(new Runnable() { @Override public void run() { + // Scan once initially + ControllerManager.detectControllers(); while (true) { updateControllerStates(); - ControllerManager.detectControllers(); + if (Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS) { + ControllerManager.detectControllers(); + } Utilities.sleep(Settings.DETECT_CONTROLLER_INTERVAL); } } diff --git a/src/net/ash/HIDToVPADNetworkClient/manager/ControllerManager.java b/src/net/ash/HIDToVPADNetworkClient/manager/ControllerManager.java index e3f6c8d..eb28953 100644 --- a/src/net/ash/HIDToVPADNetworkClient/manager/ControllerManager.java +++ b/src/net/ash/HIDToVPADNetworkClient/manager/ControllerManager.java @@ -52,7 +52,8 @@ import purejavahidapi.HidDeviceInfo; @Log public final class ControllerManager { - private static Map attachedControllers = new HashMap(); + private static final Map attachedControllers = new HashMap(); + private static final Map connectedDevicesInfo = new HashMap(); private static boolean threwUnsatisfiedLinkError = false; @@ -63,7 +64,7 @@ public final class ControllerManager { /** * Detects all attached controller. */ - @Synchronized("attachedControllers") + public static void detectControllers() { Map connectedDevices = new HashMap(); @@ -77,20 +78,30 @@ public final class ControllerManager { // Remove detached devices List toRemove = new ArrayList(); - for (String s : attachedControllers.keySet()) { - if (!connectedDevices.containsKey(s)) { - toRemove.add(s); + synchronized (attachedControllers) { + for (String s : attachedControllers.keySet()) { + System.out.println(s); + if (!connectedDevices.containsKey(s)) { + toRemove.add(s); + } } } + for (String remove : toRemove) { - attachedControllers.get(remove).destroyAll(); - attachedControllers.remove(remove); + synchronized (attachedControllers) { + attachedControllers.get(remove).destroyAll(); + attachedControllers.remove(remove); + } } // Add attached devices! for (Entry entry : connectedDevices.entrySet()) { String deviceIdentifier = entry.getKey(); - if (!attachedControllers.containsKey(deviceIdentifier)) { + boolean contains = false; + synchronized (attachedControllers) { + contains = attachedControllers.containsKey(deviceIdentifier); + } + if (!contains) { Controller c = null; switch (entry.getValue()) { case PureJAVAHid: @@ -131,7 +142,9 @@ public final class ControllerManager { c.setActive(true); } new Thread(c).start(); - attachedControllers.put(deviceIdentifier, c); + synchronized (attachedControllers) { + attachedControllers.put(deviceIdentifier, c); + } } } } @@ -144,12 +157,13 @@ public final class ControllerManager { private static Map detectHIDDevices() { Map connectedDevices = new HashMap(); - + System.out.println("detectHIDDevices"); for (HidDeviceInfo info : PureJavaHidApiManager.getAttachedController()) { String path = info.getPath(); - - if (Settings.isMacOSX()) path = path.substring(0, 13); connectedDevices.put(path, ControllerType.PureJAVAHid); + synchronized (connectedDevicesInfo) { + connectedDevicesInfo.put(path, info); + } } return connectedDevices; @@ -214,10 +228,10 @@ public final class ControllerManager { return result; } - @Synchronized("attachedControllers") public static List getActiveControllers() { List active = new ArrayList(); - for (Controller c : attachedControllers.values()) { + List attached = getAttachedControllers(); + for (Controller c : attached) { if (c.isActive()) { active.add(c); } @@ -225,11 +239,16 @@ public final class ControllerManager { return active; } - @Synchronized("attachedControllers") public static void deactivateAllAttachedControllers() { - for (Controller c : attachedControllers.values()) { + List attached = getAttachedControllers(); + for (Controller c : attached) { c.setActive(false); } } + @Synchronized("connectedDevicesInfo") + public static HidDeviceInfo getDeviceInfoByPath(String path) { + return connectedDevicesInfo.get(path); + } + } diff --git a/src/net/ash/HIDToVPADNetworkClient/network/NetworkManager.java b/src/net/ash/HIDToVPADNetworkClient/network/NetworkManager.java index 3ada071..595d674 100644 --- a/src/net/ash/HIDToVPADNetworkClient/network/NetworkManager.java +++ b/src/net/ash/HIDToVPADNetworkClient/network/NetworkManager.java @@ -161,6 +161,18 @@ public final class NetworkManager implements Runnable { private void sendPing(PingCommand command) { if (sendTCP(Protocol.getRawPingDataToSend(command))) { log.info("PING"); + byte pong; + try { + pong = tcpClient.recvByte(); + if (pong != Protocol.TCP_CMD_PONG) { + disconnect(); + } + log.info("got PONG!"); + } catch (IOException e) { + log.info("Failed to get PONG. Disconnecting."); + tcpClient.checkShouldRetry(); + } + } else { log.info("Sending the PING failed"); } diff --git a/src/net/ash/HIDToVPADNetworkClient/network/Protocol.java b/src/net/ash/HIDToVPADNetworkClient/network/Protocol.java index 6077dd1..9c36f37 100644 --- a/src/net/ash/HIDToVPADNetworkClient/network/Protocol.java +++ b/src/net/ash/HIDToVPADNetworkClient/network/Protocol.java @@ -41,6 +41,7 @@ final class Protocol { static final byte TCP_CMD_ATTACH = 0x01; static final byte TCP_CMD_DETACH = 0x02; static final byte TCP_CMD_PING = (byte) 0xF0; + static final byte TCP_CMD_PONG = (byte) 0xF1; static final byte UDP_CMD_DATA = 0x03; diff --git a/src/net/ash/HIDToVPADNetworkClient/network/TCPClient.java b/src/net/ash/HIDToVPADNetworkClient/network/TCPClient.java index 70c6db7..4b59fd4 100644 --- a/src/net/ash/HIDToVPADNetworkClient/network/TCPClient.java +++ b/src/net/ash/HIDToVPADNetworkClient/network/TCPClient.java @@ -90,20 +90,24 @@ final class TCPClient { out.write(rawCommand); out.flush(); } catch (IOException e) { - try { - if (shouldRetry++ < Settings.MAXIMUM_TRIES_FOR_RECONNECTING) { - log.info("Trying again to connect! Attempt number " + shouldRetry); - connect(ip); - } else { - abort(); - } - } catch (Exception e1) { - // e1.printStackTrace(); - } + checkShouldRetry(); throw e; } } + protected void checkShouldRetry() { + try { + if (shouldRetry++ < Settings.MAXIMUM_TRIES_FOR_RECONNECTING) { + log.info("Trying again to connect! Attempt number " + shouldRetry); + connect(ip); + } else { + abort(); + } + } catch (Exception e1) { + // e1.printStackTrace(); + } + } + void send(int value) throws IOException { send(ByteBuffer.allocate(4).putInt(value).array()); } diff --git a/src/net/ash/HIDToVPADNetworkClient/util/PureJavaHidApiManager.java b/src/net/ash/HIDToVPADNetworkClient/util/PureJavaHidApiManager.java index 2464926..78fad0e 100644 --- a/src/net/ash/HIDToVPADNetworkClient/util/PureJavaHidApiManager.java +++ b/src/net/ash/HIDToVPADNetworkClient/util/PureJavaHidApiManager.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import net.ash.HIDToVPADNetworkClient.manager.ControllerManager; import purejavahidapi.HidDevice; import purejavahidapi.HidDeviceInfo; import purejavahidapi.PureJavaHidApi; @@ -43,25 +44,17 @@ public final class PureJavaHidApiManager { * @throws IOException */ public static HidDevice getDeviceByPath(String path) throws IOException { - List devList = PureJavaHidApi.enumerateDevices(); - HidDevice result = null; - for (HidDeviceInfo info : devList) { - result = openDeviceByPath(info, path); - if (result != null) return result; + HidDeviceInfo deviceinfo = ControllerManager.getDeviceInfoByPath(path); + if (deviceinfo != null) { + HidDevice result = PureJavaHidApi.openDevice(deviceinfo); + if (result != null) { + return result; + } } - return result; - } - - private static HidDevice openDeviceByPath(HidDeviceInfo info, String expected_path) throws IOException { - if (info == null) return null; - String real_path = info.getPath(); - - if (Settings.isMacOSX()) real_path = real_path.substring(0, 13); - - if (real_path.equals(expected_path)) { - return PureJavaHidApi.openDevice(info); - } - + /* + * List devList = PureJavaHidApi.enumerateDevices(); HidDevice result = null; for (HidDeviceInfo info : devList) { String real_path = + * info.getPath(); if (real_path.equals(path)) { return PureJavaHidApi.openDevice(info); } } + */ return null; } @@ -69,14 +62,35 @@ public final class PureJavaHidApiManager { List connectedGamepads = new ArrayList(); for (HidDeviceInfo info : PureJavaHidApi.enumerateDevices()) { - if (info.getUsagePage() == 0x05 ||info.getUsagePage() == 0x01 || info.getUsagePage() == 0x04 || (info.getVendorId() == 0x57e) || (info.getVendorId() == 0x054c)) { - if(((info.getVendorId() == 0x045e) && ((info.getProductId() == 0x02ff) || (info.getProductId() == 0x02a1))) && Settings.isWindows()){ //Skip Xbox pads on windows. We have XInput + if (isGamepad(info)) { + // Skip Xbox controller under windows. We should use XInput instead. + if (isXboxController(info) && Settings.isWindows()) { continue; } connectedGamepads.add(info); } } - return connectedGamepads; } -} \ No newline at end of file + + public static boolean isGamepad(HidDeviceInfo info) { + if (info == null) return false; + short usagePage = info.getUsagePage(); + return (usagePage == 0x05 || usagePage == 0x01 || usagePage == 0x04 || isNintendoController(info) || isPlaystationController(info)); + } + + private static boolean isPlaystationController(HidDeviceInfo info) { + if (info == null) return false; + return (info.getVendorId() == 0x054c); + } + + private static boolean isNintendoController(HidDeviceInfo info) { + if (info == null) return false; + return (info.getVendorId() == 0x57e); + } + + private static boolean isXboxController(HidDeviceInfo info) { + if (info == null) return false; + return (info.getVendorId() == 0x045e) && ((info.getProductId() == 0x02ff) || (info.getProductId() == 0x02a1)); + } +} diff --git a/src/net/ash/HIDToVPADNetworkClient/util/Settings.java b/src/net/ash/HIDToVPADNetworkClient/util/Settings.java index 17d879a..f1a0b58 100644 --- a/src/net/ash/HIDToVPADNetworkClient/util/Settings.java +++ b/src/net/ash/HIDToVPADNetworkClient/util/Settings.java @@ -44,9 +44,11 @@ public final class Settings { public static final int PING_INTERVAL = 1000; public static final int PROCESS_CMD_INTERVAL = 10; + public static boolean SCAN_AUTOMATICALLY_FOR_CONTROLLERS = !isMacOSX(); // It doesn't work on OSX + public static boolean DEBUG_UDP_OUTPUT = false; public static boolean SEND_DATA_ONLY_ON_CHANGE = false; - public static boolean AUTO_ACTIVATE_CONTROLLER = true; + public static boolean AUTO_ACTIVATE_CONTROLLER = false; @Getter @Setter private static String ipAddr = "192.168.0.35"; // @Maschell, you're welcome @@ -88,6 +90,7 @@ public final class Settings { Settings.ipAddr = prop.getProperty("ipAddr"); String autoActivatingControllerString = prop.getProperty("autoActivatingController"); String sendDataOnlyOnChanges = prop.getProperty("sendDataOnlyOnChanges"); + String scanAutomaticallyForControllers = prop.getProperty("scanAutomaticallyForControllers"); if (autoActivatingControllerString != null) { // We don't combine the if statements to keep the default value. if ("true".equals(autoActivatingControllerString)) { @@ -103,6 +106,13 @@ public final class Settings { Settings.SEND_DATA_ONLY_ON_CHANGE = false; } } + if (scanAutomaticallyForControllers != null) { // We don't combine the if statements to keep the default value. + if ("true".equals(scanAutomaticallyForControllers)) { + Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS = true; + } else { + Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS = false; + } + } log.info("Loaded config successfully!"); } @@ -125,6 +135,7 @@ public final class Settings { prop.setProperty("ipAddr", Settings.ipAddr); prop.setProperty("autoActivatingController", Boolean.toString(Settings.AUTO_ACTIVATE_CONTROLLER)); prop.setProperty("sendDataOnlyOnChanges", Boolean.toString(Settings.SEND_DATA_ONLY_ON_CHANGE)); + prop.setProperty("scanAutomaticallyForControllers", Boolean.toString(Settings.SCAN_AUTOMATICALLY_FOR_CONTROLLERS)); try { FileOutputStream outStream = new FileOutputStream(configFile);