diff --git a/src/config-tool/.gitignore b/src/config-tool/.gitignore
new file mode 100644
index 00000000..e8d03113
--- /dev/null
+++ b/src/config-tool/.gitignore
@@ -0,0 +1 @@
+/.metadata
diff --git a/src/config-tool/ConfigTool/.classpath b/src/config-tool/ConfigTool/.classpath
new file mode 100644
index 00000000..cd43896c
--- /dev/null
+++ b/src/config-tool/ConfigTool/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/config-tool/ConfigTool/.gitignore b/src/config-tool/ConfigTool/.gitignore
new file mode 100644
index 00000000..77237710
--- /dev/null
+++ b/src/config-tool/ConfigTool/.gitignore
@@ -0,0 +1,2 @@
+/.settings
+/classes
diff --git a/src/config-tool/ConfigTool/.project b/src/config-tool/ConfigTool/.project
new file mode 100644
index 00000000..9e7af111
--- /dev/null
+++ b/src/config-tool/ConfigTool/.project
@@ -0,0 +1,17 @@
+
+
+ ConfigTool
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/HyperionConfigApplet.java b/src/config-tool/ConfigTool/src/org/hyperion/config/HyperionConfigApplet.java
new file mode 100644
index 00000000..0b5292fe
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/HyperionConfigApplet.java
@@ -0,0 +1,23 @@
+package org.hyperion.config;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+
+import javax.swing.JApplet;
+
+import org.hyperion.config.gui.ConfigPanel;
+
+public class HyperionConfigApplet extends JApplet {
+
+ public HyperionConfigApplet() {
+ super();
+
+ initialise();
+ }
+
+ private void initialise() {
+ setPreferredSize(new Dimension(600, 300));
+
+ add(new ConfigPanel(), BorderLayout.CENTER);
+ }
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/LedFrameFactory.java b/src/config-tool/ConfigTool/src/org/hyperion/config/LedFrameFactory.java
new file mode 100644
index 00000000..af326191
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/LedFrameFactory.java
@@ -0,0 +1,165 @@
+package org.hyperion.config;
+
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Vector;
+
+import org.hyperion.config.spec.BorderSide;
+import org.hyperion.config.spec.Led;
+import org.hyperion.config.spec.LedFrameConstruction;
+
+public class LedFrameFactory {
+
+ private static int increase(LedFrameConstruction frameSpec, int pLedCounter) {
+ if (frameSpec.clockwiseDirection) {
+ return (pLedCounter+1)%frameSpec.getLedCount();
+ } else {
+ if (pLedCounter == 0) {
+ return frameSpec.getLedCount() - 1;
+ }
+ return pLedCounter -1;
+ }
+
+ }
+
+ public static Vector construct(LedFrameConstruction frameSpec) {
+ double overlap_frac = 0.50;
+
+ Vector mLeds = new Vector<>();
+
+ int totalLedCount = frameSpec.getLedCount();
+ if (totalLedCount <= 0) {
+ return mLeds;
+ }
+
+ int iLed = (totalLedCount - frameSpec.firstLedOffset)%totalLedCount;
+ if (iLed < 0) {
+ iLed += totalLedCount;
+ }
+ if (frameSpec.topLeftCorner) {
+ mLeds.add(createLed(frameSpec, iLed, 0.0, 0.0, overlap_frac, BorderSide.top_left));
+ iLed = increase(frameSpec, iLed);
+ }
+ if (frameSpec.topLedCnt > 0) {
+ int ledCnt = frameSpec.topLedCnt;
+ double ledSpacing = (double)1.0/(ledCnt);
+ for (int iTop=0; iTop 0) {
+ int ledCnt = frameSpec.rightLedCnt;
+ double ledSpacing = 1.0/ledCnt;
+ for (int iRight=0; iRight 0) {
+ int ledCnt = frameSpec.topLedCnt;
+
+ double ledSpacing = (double)1.0/ledCnt;
+ for (int iBottom=(ledCnt-1); iBottom>=0; --iBottom) {
+ if (iBottom > (frameSpec.bottomLedCnt-1)/2 && iBottom < ledCnt - frameSpec.bottomLedCnt/2) {
+ continue;
+ }
+ double led_x = ledSpacing/2.0 + iBottom * ledSpacing;
+ double led_y = 1.0;
+
+ mLeds.add(createLed(frameSpec, iLed, led_x, led_y, overlap_frac, BorderSide.bottom));
+ iLed = increase(frameSpec, iLed);
+ }
+ }
+ if (frameSpec.bottomLeftCorner) {
+ mLeds.add(createLed(frameSpec, iLed, 0.0, 1.0, overlap_frac, BorderSide.bottom_left));
+ iLed = increase(frameSpec, iLed);
+ }
+ if (frameSpec.leftLedCnt > 0) {
+ int ledCnt = frameSpec.leftLedCnt;
+ double ledSpacing = (double)1.0/ledCnt;
+ for (int iRight=(ledCnt-1); iRight>=0; --iRight) {
+ double led_x = 0.0;
+ double led_y = ledSpacing/2.0 + iRight * ledSpacing;
+
+ mLeds.add(createLed(frameSpec, iLed, led_x, led_y, overlap_frac, BorderSide.left));
+ iLed = increase(frameSpec, iLed);
+ }
+ }
+
+ return mLeds;
+ }
+
+ private static Led createLed(LedFrameConstruction frameSpec, int seqNr, double x_frac, double y_frac, double overlap_frac, BorderSide pBorderSide) {
+ Led led = new Led();
+ led.mLedSeqNr = seqNr;
+ led.mLocation = new Point2D.Double(x_frac, y_frac);
+ led.mSide = pBorderSide;
+
+ double widthFrac = (1.0/frameSpec.topLedCnt * (1.0 + overlap_frac))/2.0;
+ double heightFrac = (1.0/frameSpec.leftLedCnt * (1.0 + overlap_frac))/2.0;
+
+ switch (pBorderSide) {
+ case top_left: {
+ led.mImageRectangle = new Rectangle2D.Double(0.0, 0.0, frameSpec.verticalDepth, frameSpec.horizontalDepth);
+ break;
+ }
+ case top_right: {
+ led.mImageRectangle = new Rectangle2D.Double(1.0-frameSpec.verticalDepth, 0.0, frameSpec.verticalDepth, frameSpec.horizontalDepth);
+ break;
+ }
+ case bottom_left: {
+ led.mImageRectangle = new Rectangle2D.Double(0.0, 1.0-frameSpec.horizontalDepth, frameSpec.verticalDepth, frameSpec.horizontalDepth);
+ break;
+ }
+ case bottom_right: {
+ led.mImageRectangle = new Rectangle2D.Double(1.0-frameSpec.verticalDepth, 1.0-frameSpec.horizontalDepth, frameSpec.verticalDepth, frameSpec.horizontalDepth);
+ break;
+ }
+ case top:{
+ double intXmin_frac = Math.max(0.0, x_frac-widthFrac);
+ double intXmax_frac = Math.min(x_frac+widthFrac, 1.0);
+ led.mImageRectangle = new Rectangle2D.Double(intXmin_frac, 0.0, intXmax_frac-intXmin_frac, frameSpec.horizontalDepth);
+
+ break;
+ }
+ case bottom:
+ {
+ double intXmin_frac = Math.max(0.0, x_frac-widthFrac);
+ double intXmax_frac = Math.min(x_frac+widthFrac, 1.0);
+
+ led.mImageRectangle = new Rectangle2D.Double(intXmin_frac, 1.0-frameSpec.horizontalDepth, intXmax_frac-intXmin_frac, frameSpec.horizontalDepth);
+ break;
+ }
+ case left: {
+ double intYmin_frac = Math.max(0.0, y_frac-heightFrac);
+ double intYmax_frac = Math.min(y_frac+heightFrac, 1.0);
+ led.mImageRectangle = new Rectangle2D.Double(0.0, intYmin_frac, frameSpec.verticalDepth, intYmax_frac-intYmin_frac);
+ break;
+ }
+ case right:
+ double intYmin_frac = Math.max(0.0, y_frac-heightFrac);
+ double intYmax_frac = Math.min(y_frac+heightFrac, 1.0);
+ led.mImageRectangle = new Rectangle2D.Double(1.0-frameSpec.verticalDepth, intYmin_frac, frameSpec.verticalDepth, intYmax_frac-intYmin_frac);
+ break;
+ }
+
+ return led;
+ }
+
+
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/LedString.java b/src/config-tool/ConfigTool/src/org/hyperion/config/LedString.java
new file mode 100644
index 00000000..c7d3d68f
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/LedString.java
@@ -0,0 +1,74 @@
+package org.hyperion.config;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Vector;
+
+import org.hyperion.config.spec.ColorConfig;
+import org.hyperion.config.spec.DeviceConfig;
+import org.hyperion.config.spec.Led;
+import org.hyperion.config.spec.MiscConfig;
+
+public class LedString {
+ /** The individual led configuration */
+ public Vector leds;
+
+ /** The configuration of the output device */
+ DeviceConfig mDeviceConfig = new DeviceConfig();
+
+ /** The color adjustment configuration */
+ ColorConfig mColorConfig = new ColorConfig();
+
+ /** The miscellaneous configuration (bootsequence, blackborder detector, etc) */
+ MiscConfig mMiscConfig = new MiscConfig();
+
+ public void saveConfigFile(String mFilename) throws IOException {
+
+ try (FileWriter fw = new FileWriter(mFilename)) {
+ fw.write("// Automatically generated configuration file for 'Hyperion'\n");
+ fw.write("// Generated by: 'Hyperion configuration Tool\n");
+ fw.write("\n");
+ fw.write("{\n");
+
+ String deviceJson = mDeviceConfig.toJsonString();
+ fw.write(deviceJson + ",\n");
+
+ String colorJson = mColorConfig.toJsonString();
+ fw.write(colorJson + ",\n");
+
+ String ledJson = ledToJsonString();
+ fw.write(ledJson + ",\n");
+
+ String miscJson = mMiscConfig.toJsonString();
+ fw.write(miscJson + "\n");
+
+ fw.write("}\n");
+ } catch (IOException e) {
+ throw e;
+ }
+ }
+
+ String ledToJsonString() {
+ StringBuffer strBuf = new StringBuffer();
+ strBuf.append("\t\"leds\" : \n");
+ strBuf.append("\t[\n");
+
+ for (Led led : leds)
+ {
+ strBuf.append("\t\t{\n");
+ strBuf.append(String.format(Locale.ROOT, "\t\t\t\"index\" : %d,\n", led.mLedSeqNr));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\t\"hscan\" : { \"minimum\" : %.4f, \"maximum\" : %.4f },\n", led.mImageRectangle.getMinX(), led.mImageRectangle.getMaxX()));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\t\"vscan\" : { \"minimum\" : %.4f, \"maximum\" : %.4f }\n", led.mImageRectangle.getMinY(), led.mImageRectangle.getMaxY()));
+ if (led != leds.lastElement()) {
+ strBuf.append("\t\t},\n");
+ } else {
+ strBuf.append("\t\t}\n");
+ }
+ }
+
+ strBuf.append("\t]");
+
+ return strBuf.toString();
+ }
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/Main.java b/src/config-tool/ConfigTool/src/org/hyperion/config/Main.java
new file mode 100644
index 00000000..2405c8df
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/Main.java
@@ -0,0 +1,24 @@
+package org.hyperion.config;
+
+import javax.swing.JFrame;
+import javax.swing.UIManager;
+
+import org.hyperion.config.gui.ConfigPanel;
+
+public class Main {
+
+ public static void main(String[] pArgs) {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception e) {}
+
+ JFrame frame = new JFrame();
+ frame.setTitle("Hyperion configuration Tool");
+ frame.setSize(1300, 600);
+ frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+
+ frame.setContentPane(new ConfigPanel());
+
+ frame.setVisible(true);
+ }
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/ColorConfigPanel.java b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/ColorConfigPanel.java
new file mode 100644
index 00000000..31b66e5b
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/ColorConfigPanel.java
@@ -0,0 +1,209 @@
+package org.hyperion.config.gui;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.GroupLayout;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerNumberModel;
+
+public class ColorConfigPanel extends JPanel {
+ private JPanel mRgbTransformPanel;
+ private JLabel mThresholdLabel;
+ private JLabel mGammaLabel;
+ private JLabel mBlacklevelLabel;
+ private JLabel mWhitelevelLabel;
+ private JLabel mRedTransformLabel;
+ private JSpinner mRedThresholdSpinner;
+ private JSpinner mRedGammaSpinner;
+ private JSpinner mRedBlacklevelSpinner;
+ private JSpinner mRedWhitelevelSpinner;
+ private JLabel mGreenTransformLabel;
+ private JSpinner mGreenThresholdSpinner;
+ private JSpinner mGreenGammaSpinner;
+ private JSpinner mGreenBlacklevelSpinner;
+ private JSpinner mGreenWhitelevelSpinner;
+ private JLabel mBlueTransformLabel;
+ private JSpinner mBlueThresholdSpinner;
+ private JSpinner mBlueGammaSpinner;
+ private JSpinner mBlueBlacklevelSpinner;
+ private JSpinner mBlueWhitelevelSpinner;
+
+ private JPanel mHsvTransformPanel;
+ private JLabel mSaturationAdjustLabel;
+ private JSpinner mSaturationAdjustSpinner;
+ private JLabel mValueAdjustLabel;
+ private JSpinner mValueAdjustSpinner;
+
+ public ColorConfigPanel() {
+ super();
+
+ initialise();
+ }
+
+ private void initialise() {
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+
+ add(getRgbPanel());
+ add(getHsvPanel());
+ }
+
+ private JPanel getRgbPanel() {
+ if (mRgbTransformPanel == null) {
+ mRgbTransformPanel = new JPanel();
+
+ GroupLayout layout = new GroupLayout(mRgbTransformPanel);
+ mRgbTransformPanel.setLayout(layout);
+
+ mThresholdLabel = new JLabel("Thresold");
+ mRgbTransformPanel.add(mThresholdLabel);
+
+ mGammaLabel = new JLabel("Gamma");
+ mRgbTransformPanel.add(mGammaLabel);
+
+ mBlacklevelLabel = new JLabel("Blacklevel");
+ mRgbTransformPanel.add(mBlacklevelLabel);
+
+ mWhitelevelLabel = new JLabel("Whitelevel");
+ mRgbTransformPanel.add(mWhitelevelLabel);
+
+ mRedTransformLabel = new JLabel("RED");
+ mRgbTransformPanel.add(mRedTransformLabel);
+ mRedThresholdSpinner = new JSpinner(new SpinnerNumberModel());
+ mRgbTransformPanel.add(mRedThresholdSpinner);
+ mRedGammaSpinner = new JSpinner(new SpinnerNumberModel());
+ mRgbTransformPanel.add(mRedGammaSpinner);
+ mRedBlacklevelSpinner = new JSpinner(new SpinnerNumberModel());
+ mRgbTransformPanel.add(mRedBlacklevelSpinner);
+ mRedWhitelevelSpinner = new JSpinner(new SpinnerNumberModel());
+ mRgbTransformPanel.add(mRedWhitelevelSpinner);
+
+ mGreenTransformLabel = new JLabel("GREEN");
+ mRgbTransformPanel.add(mGreenTransformLabel);
+ mGreenThresholdSpinner = new JSpinner(new SpinnerNumberModel());
+ mRgbTransformPanel.add(mGreenThresholdSpinner);
+ mGreenGammaSpinner = new JSpinner(new SpinnerNumberModel());
+ mRgbTransformPanel.add(mGreenGammaSpinner);
+ mGreenBlacklevelSpinner = new JSpinner(new SpinnerNumberModel());
+ mRgbTransformPanel.add(mGreenBlacklevelSpinner);
+ mGreenWhitelevelSpinner = new JSpinner(new SpinnerNumberModel());
+ mRgbTransformPanel.add(mGreenWhitelevelSpinner);
+
+ mBlueTransformLabel = new JLabel("BLUE");
+ mRgbTransformPanel.add(mBlueTransformLabel);
+ mBlueThresholdSpinner = new JSpinner(new SpinnerNumberModel());
+ mRgbTransformPanel.add(mBlueThresholdSpinner);
+ mBlueGammaSpinner = new JSpinner(new SpinnerNumberModel());
+ mRgbTransformPanel.add(mBlueGammaSpinner);
+ mBlueBlacklevelSpinner = new JSpinner(new SpinnerNumberModel());
+ mRgbTransformPanel.add(mBlueBlacklevelSpinner);
+ mBlueWhitelevelSpinner = new JSpinner(new SpinnerNumberModel());
+ mRgbTransformPanel.add(mBlueWhitelevelSpinner);
+
+ layout.setHorizontalGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mRedTransformLabel)
+ .addComponent(mGreenTransformLabel)
+ .addComponent(mBlueTransformLabel))
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mThresholdLabel)
+ .addComponent(mRedThresholdSpinner)
+ .addComponent(mGreenThresholdSpinner)
+ .addComponent(mBlueThresholdSpinner))
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mGammaLabel)
+ .addComponent(mRedGammaSpinner)
+ .addComponent(mGreenGammaSpinner)
+ .addComponent(mBlueGammaSpinner)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mBlacklevelLabel)
+ .addComponent(mRedBlacklevelSpinner)
+ .addComponent(mGreenBlacklevelSpinner)
+ .addComponent(mBlueBlacklevelSpinner)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mWhitelevelLabel)
+ .addComponent(mRedWhitelevelSpinner)
+ .addComponent(mGreenWhitelevelSpinner)
+ .addComponent(mBlueWhitelevelSpinner)
+ ));
+
+ layout.setVerticalGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mThresholdLabel)
+ .addComponent(mGammaLabel)
+ .addComponent(mBlacklevelLabel)
+ .addComponent(mWhitelevelLabel))
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mRedTransformLabel)
+ .addComponent(mRedThresholdSpinner)
+ .addComponent(mRedGammaSpinner)
+ .addComponent(mRedBlacklevelSpinner)
+ .addComponent(mRedWhitelevelSpinner)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mGreenTransformLabel)
+ .addComponent(mGreenThresholdSpinner)
+ .addComponent(mGreenGammaSpinner)
+ .addComponent(mGreenBlacklevelSpinner)
+ .addComponent(mGreenWhitelevelSpinner)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mBlueTransformLabel)
+ .addComponent(mBlueThresholdSpinner)
+ .addComponent(mBlueGammaSpinner)
+ .addComponent(mBlueBlacklevelSpinner)
+ .addComponent(mBlueWhitelevelSpinner)
+ ));
+ }
+ return mRgbTransformPanel;
+ }
+
+ private JPanel getHsvPanel() {
+ if (mHsvTransformPanel == null) {
+ mHsvTransformPanel = new JPanel();
+ mHsvTransformPanel.setBorder(BorderFactory.createTitledBorder("HSV"));
+
+ GroupLayout layout = new GroupLayout(mHsvTransformPanel);
+ mHsvTransformPanel.setLayout(layout);
+
+ mSaturationAdjustLabel = new JLabel("Saturation");
+ mHsvTransformPanel.add(mSaturationAdjustLabel);
+
+ mSaturationAdjustSpinner = new JSpinner(new SpinnerNumberModel(1.0, 0.0, 1024.0, 0.01));
+ mHsvTransformPanel.add(mSaturationAdjustSpinner);
+
+ mValueAdjustLabel = new JLabel("Value");
+ mHsvTransformPanel.add(mValueAdjustLabel);
+
+ mValueAdjustSpinner = new JSpinner(new SpinnerNumberModel(1.0, 0.0, 1024.0, 0.01));
+ mHsvTransformPanel.add(mValueAdjustSpinner);
+
+ layout.setHorizontalGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mSaturationAdjustLabel)
+ .addComponent(mValueAdjustLabel)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mSaturationAdjustSpinner)
+ .addComponent(mValueAdjustSpinner)
+ )
+ );
+
+ layout.setVerticalGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mSaturationAdjustLabel)
+ .addComponent(mSaturationAdjustSpinner)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mValueAdjustLabel)
+ .addComponent(mValueAdjustSpinner)
+ )
+ );
+ }
+ return mHsvTransformPanel;
+ }
+
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/ConfigPanel.java b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/ConfigPanel.java
new file mode 100644
index 00000000..cb2bf78b
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/ConfigPanel.java
@@ -0,0 +1,206 @@
+package org.hyperion.config.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.GroupLayout;
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.hyperion.config.LedFrameFactory;
+import org.hyperion.config.LedString;
+import org.hyperion.config.spec.LedFrameConstruction;
+
+public class ConfigPanel extends JPanel {
+
+ private final LedFrameConstruction mLedFrameSpec = new LedFrameConstruction();
+
+ private final Action mSaveConfigAction = new AbstractAction("Create Hyperion Configuration") {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ JFileChooser fileChooser = new JFileChooser();
+ fileChooser.showSaveDialog(ConfigPanel.this);
+
+ LedString ledString = new LedString();
+ ledString.leds = LedFrameFactory.construct(mLedFrameSpec);
+
+ try {
+ ledString.saveConfigFile(fileChooser.getSelectedFile().getAbsolutePath());
+ } catch (IOException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ }
+ };
+
+ private JPanel mTvPanel;
+ private JHyperionTv mHyperionTv;
+
+ private JPanel mConstructionPanel;
+
+ private JPanel mIntegrationPanel;
+
+ private JLabel mHorizontalDepthLabel;
+ private JSpinner mHorizontalDepthSpinner;
+ private JLabel mVerticalDepthLabel;
+ private JSpinner mVerticalDepthSpinner;
+
+ private JPanel mSpecificationPanel;
+
+ private MiscConfigPanel mMiscPanel;
+
+ private JButton mSaveConfigButton;
+
+ public ConfigPanel() {
+ super();
+
+ mLedFrameSpec.clockwiseDirection = true;
+
+ mLedFrameSpec.topLeftCorner = true;
+ mLedFrameSpec.topRightCorner= true;
+ mLedFrameSpec.bottomLeftCorner= true;
+ mLedFrameSpec.bottomRightCorner= true;
+
+ mLedFrameSpec.topLedCnt = 16;
+ mLedFrameSpec.bottomLedCnt = 16;
+ mLedFrameSpec.leftLedCnt = 7;
+ mLedFrameSpec.rightLedCnt = 7;
+
+ mLedFrameSpec.firstLedOffset = 0;
+
+ initialise();
+
+ mHyperionTv.setLeds(LedFrameFactory.construct(mLedFrameSpec));
+ mLedFrameSpec.addObserver(new Observer() {
+ @Override
+ public void update(Observable o, Object arg) {
+ mHyperionTv.setLeds(LedFrameFactory.construct(mLedFrameSpec));
+ mHyperionTv.repaint();
+ }
+ });
+ }
+
+ private void initialise() {
+ setLayout(new BorderLayout());
+
+ add(getTvPanel(), BorderLayout.CENTER);
+ add(getSpecificationPanel(), BorderLayout.WEST);
+
+ }
+
+ private JPanel getTvPanel() {
+ if (mTvPanel == null) {
+ mTvPanel = new JPanel();
+ mTvPanel.setLayout(new BorderLayout());
+
+ mHyperionTv = new JHyperionTv();
+ mTvPanel.add(mHyperionTv, BorderLayout.CENTER);
+ }
+ return mTvPanel;
+ }
+
+ private JPanel getSpecificationPanel() {
+ if (mSpecificationPanel == null) {
+ mSpecificationPanel = new JPanel();
+ mSpecificationPanel.setPreferredSize(new Dimension(300, 200));
+ mSpecificationPanel.setLayout(new BoxLayout(mSpecificationPanel, BoxLayout.Y_AXIS));
+
+ mConstructionPanel = new LedFramePanel(mLedFrameSpec);
+ mConstructionPanel.setBorder(BorderFactory.createTitledBorder("Construction"));
+ mSpecificationPanel.add(mConstructionPanel);
+
+ mSpecificationPanel.add(getIntegrationPanel());
+
+ mMiscPanel = new MiscConfigPanel();
+ mMiscPanel.setBorder(BorderFactory.createTitledBorder("Misc"));
+ mSpecificationPanel.add(mMiscPanel);
+
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+ mSaveConfigButton = new JButton(mSaveConfigAction);
+ panel.add(mSaveConfigButton, BorderLayout.SOUTH);
+ mSpecificationPanel.add(panel);
+ }
+ return mSpecificationPanel;
+ }
+
+ private JPanel getIntegrationPanel() {
+ if (mIntegrationPanel == null) {
+ mIntegrationPanel = new JPanel();
+ mIntegrationPanel.setBorder(BorderFactory.createTitledBorder("Image Process"));
+
+ mHorizontalDepthLabel = new JLabel("Horizontal depth:");
+ mHorizontalDepthLabel.setPreferredSize(new Dimension(100, 30));
+ mHorizontalDepthLabel.setMaximumSize(new Dimension(150, 30));
+ mIntegrationPanel.add(mHorizontalDepthLabel);
+
+ mHorizontalDepthSpinner = new JSpinner(new SpinnerNumberModel(0.05, 0.01, 1.0, 0.01));
+ mHorizontalDepthSpinner.setPreferredSize(new Dimension(150, 30));
+ mHorizontalDepthSpinner.setMaximumSize(new Dimension(250, 30));
+ mHorizontalDepthSpinner.addChangeListener(mChangeListener);
+ mIntegrationPanel.add(mHorizontalDepthSpinner);
+
+ mVerticalDepthLabel = new JLabel("Vertical depth:");
+ mVerticalDepthLabel.setPreferredSize(new Dimension(100, 30));
+ mVerticalDepthLabel.setMaximumSize(new Dimension(150, 30));
+ mIntegrationPanel.add(mVerticalDepthLabel);
+
+ mVerticalDepthSpinner = new JSpinner(new SpinnerNumberModel(0.05, 0.01, 1.0, 0.01));
+ mVerticalDepthSpinner.setPreferredSize(new Dimension(150, 30));
+ mVerticalDepthSpinner.setMaximumSize(new Dimension(250, 30));
+ mVerticalDepthSpinner.addChangeListener(mChangeListener);
+ mIntegrationPanel.add(mVerticalDepthSpinner);
+
+ GroupLayout layout = new GroupLayout(mIntegrationPanel);
+ mIntegrationPanel.setLayout(layout);
+
+ layout.setHorizontalGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mHorizontalDepthLabel)
+ .addComponent(mVerticalDepthLabel)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mHorizontalDepthSpinner)
+ .addComponent(mVerticalDepthSpinner)
+ )
+ );
+ layout.setVerticalGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mHorizontalDepthLabel)
+ .addComponent(mHorizontalDepthSpinner)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mVerticalDepthLabel)
+ .addComponent(mVerticalDepthSpinner)
+ )
+ );
+
+ }
+ return mIntegrationPanel;
+ }
+
+ private final ChangeListener mChangeListener = new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ mLedFrameSpec.horizontalDepth = (Double)mHorizontalDepthSpinner.getValue();
+ mLedFrameSpec.verticalDepth = (Double)mVerticalDepthSpinner.getValue();
+
+ mLedFrameSpec.setChanged();
+ mLedFrameSpec.notifyObservers();
+ }
+ };
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/JHyperionTv.java b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/JHyperionTv.java
new file mode 100644
index 00000000..6500e7c2
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/JHyperionTv.java
@@ -0,0 +1,333 @@
+package org.hyperion.config.gui;
+
+import java.awt.BasicStroke;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.net.URL;
+import java.util.Vector;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ImageIcon;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JPopupMenu;
+
+import org.hyperion.config.spec.Led;
+
+public class JHyperionTv extends Component {
+
+ private JPopupMenu mPopupMenu;
+ private final Action mLoadAction = new AbstractAction("Load image...") {
+ JFileChooser mImageChooser;
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (mImageChooser == null) {
+ mImageChooser = new JFileChooser();
+ }
+
+ if (mImageChooser.showOpenDialog(JHyperionTv.this) != JFileChooser.APPROVE_OPTION) {
+ return;
+ }
+ File file = mImageChooser.getSelectedFile();
+
+ try {
+ ImageIcon imageIcon = new ImageIcon(file.getAbsolutePath());
+ Image image = imageIcon.getImage();
+ mRawImage = image;
+ repaint();
+ } catch (Exception ex) {
+
+ }
+ }
+ };
+
+ private class SelectImageAction extends AbstractAction {
+ private final String mImageName;
+ SelectImageAction(String pImageName) {
+ super(pImageName);
+ mImageName = pImageName;
+
+ ImageIcon image = loadImage();
+ if (image != null) {
+ Image scaledImage = image.getImage().getScaledInstance(32, 18, Image.SCALE_SMOOTH);
+ ImageIcon scaledIcon = new ImageIcon(scaledImage, mImageName);
+ putValue(SMALL_ICON, scaledIcon);
+ }
+ }
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ ImageIcon imageIcon = loadImage();
+ if (imageIcon != null) {
+ mRawImage = imageIcon.getImage();
+ repaint();
+ }
+ }
+
+ ImageIcon loadImage() {
+ URL imageUrl = JHyperionTv.class.getResource(mImageName + ".png");
+ if (imageUrl == null) {
+ System.out.println("Failed to load image: " + mImageName);
+ return null;
+ }
+ return new ImageIcon(imageUrl);
+ }
+ }
+
+ private JPopupMenu getPopupMenu() {
+ if (mPopupMenu == null) {
+ mPopupMenu = new JPopupMenu();
+ mPopupMenu.add(mLoadAction);
+
+ JMenu selectMenu = new JMenu("Select Image");
+ selectMenu.add(new SelectImageAction("TestImage_01"));
+ selectMenu.add(new SelectImageAction("TestImage_02"));
+ selectMenu.add(new SelectImageAction("TestImage_03"));
+ selectMenu.add(new SelectImageAction("TestImage_04"));
+ selectMenu.add(new SelectImageAction("TestImage_05"));
+ selectMenu.add(new SelectImageAction("TestImageBBB_01"));
+ selectMenu.add(new SelectImageAction("TestImageBBB_02"));
+ selectMenu.add(new SelectImageAction("TestImageBBB_03"));
+ mPopupMenu.add(selectMenu);
+ }
+ return mPopupMenu;
+ }
+
+ private Image mRawImage = new ImageIcon(JHyperionTv.class.getResource("TestImage_01.png")).getImage();
+
+ int lightBorder = 100;
+ int tvBorder = 12;
+
+ private class LedWrapper {
+ public final Led led;
+
+ public int lastX = 0;
+ public int lastY = 0;
+
+ public LedWrapper(Led pLed) {
+ led = pLed;
+ }
+ }
+ private final Vector mLeds2 = new Vector<>();
+
+ public void setLeds(Vector pLeds) {
+ mLeds2.clear();
+
+ for (Led led : pLeds) {
+ mLeds2.add(new LedWrapper(led));
+ }
+ }
+
+ LedWrapper mSelLed = null;
+
+ public JHyperionTv() {
+
+ // Pre-cache the popup menu
+ getPopupMenu();
+
+ addMouseMotionListener(new MouseMotionListener() {
+ @Override
+ public void mouseMoved(MouseEvent e) {
+ mSelLed = null;
+
+ double x = (double)(e.getX() - lightBorder - tvBorder) / (getWidth() - lightBorder*2-tvBorder*2);
+ double y = (double)(e.getY() - lightBorder - tvBorder) / (getHeight() - lightBorder*2-tvBorder*2);
+
+ for (LedWrapper led : mLeds2) {
+ if (led.led.mImageRectangle.contains(x, y) || (Math.abs(led.led.mLocation.getX() - x) < 0.01 && Math.abs(led.led.mLocation.getY() - y) < 0.01)) {
+ mSelLed = led;
+ break;
+ }
+ }
+
+ repaint();
+ }
+ @Override
+ public void mouseDragged(MouseEvent e) {
+
+ }
+ });
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ showPopup(e);
+ }
+ @Override
+ public void mousePressed(MouseEvent e) {
+ showPopup(e);
+ }
+ private void showPopup(MouseEvent e) {
+ if (!e.isPopupTrigger()) {
+ return;
+ }
+ getPopupMenu().show(JHyperionTv.this, e.getX(), e.getY());
+ }
+ });
+ }
+
+ @Override
+ public void paint(Graphics g) {
+ super.paint(g);
+ if (getWidth() <= 2*lightBorder+2*tvBorder+10 || getHeight() <= 2*lightBorder+2*tvBorder+10) {
+ return;
+ }
+
+ Graphics2D g2d = (Graphics2D) g.create();
+ g2d.setColor(Color.BLACK);
+ g2d.fillRect(0, 0, getWidth(), getHeight());
+
+ int screenWidth = getWidth() - 2*lightBorder;
+ int screenHeight = getHeight() - 2*lightBorder;
+ int imageWidth = screenWidth - 2*tvBorder;
+ int imageHeight = screenHeight- 2*tvBorder;
+
+ g2d.translate((getWidth() - imageWidth)/2, (getHeight() - imageHeight)/2);
+
+ BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
+ image.getGraphics().drawImage(mRawImage, 0, 0, image.getWidth(), image.getHeight(), null);
+
+ if (mLeds2 != null) {
+ paintAllLeds(g2d, screenWidth, screenHeight, image);
+ }
+
+ g2d.setColor(Color.DARK_GRAY.darker());
+ g2d.fillRect(-tvBorder, -tvBorder, screenWidth, screenHeight);
+ g2d.drawImage(image, 0, 0, imageWidth, imageHeight, this);
+
+ paintLedNumbers(g2d);
+
+ for (LedWrapper led : mLeds2) {
+ g2d.setColor(Color.GRAY);
+
+ int xmin = (int)(led.led.mImageRectangle.getMinX() * (imageWidth-1));
+ int xmax = (int)(led.led.mImageRectangle.getMaxX()* (imageWidth-1));
+
+ int ymin = (int)(led.led.mImageRectangle.getMinY() * (imageHeight-1));
+ int ymax = (int)(led.led.mImageRectangle.getMaxY() * (imageHeight-1));
+
+ g2d.drawRect(xmin, ymin, (xmax-xmin), (ymax-ymin));
+ }
+ if (mSelLed != null) {
+ g2d.setStroke(new BasicStroke(3.0f));
+ g2d.setColor(Color.WHITE);
+
+ int xmin = (int)(mSelLed.led.mImageRectangle.getMinX() * (imageWidth-1));
+ int xmax = (int)(mSelLed.led.mImageRectangle.getMaxX()* (imageWidth-1));
+
+ int ymin = (int)(mSelLed.led.mImageRectangle.getMinY() * (imageHeight-1));
+ int ymax = (int)(mSelLed.led.mImageRectangle.getMaxY() * (imageHeight-1));
+
+ g2d.drawRect(xmin, ymin, (xmax-xmin), (ymax-ymin));
+ }
+ }
+
+ class LedPaint {
+ int xmin;
+ int xmax;
+ int ymin;
+ int ymax;
+
+ int color;
+ int seqNr;
+
+ int screenX;
+ int screenY;
+ double angle_rad;
+ }
+
+ private void paintAllLeds(Graphics2D g2d, int screenWidth, int screenHeight, BufferedImage image) {
+ Dimension screenDimension = new Dimension(getWidth()-2*lightBorder-2*tvBorder, getHeight()-2*lightBorder-2*tvBorder);
+
+ int imageWidth = image.getWidth();
+ int imageHeight = image.getHeight();
+
+ Vector ledPaints = new Vector<>();
+
+ for (LedWrapper led : mLeds2) {
+ LedPaint ledPaint = new LedPaint();
+ ledPaint.xmin = (int)(led.led.mImageRectangle.getMinX() * (imageWidth-1));
+ ledPaint.xmax = (int)(led.led.mImageRectangle.getMaxX()* (imageWidth-1));
+ ledPaint.ymin = (int)(led.led.mImageRectangle.getMinY() * (imageHeight-1));
+ ledPaint.ymax = (int)(led.led.mImageRectangle.getMaxY() * (imageHeight-1));
+
+ int red = 0;
+ int green = 0;
+ int blue = 0;
+ int count = 0;
+
+ for (int y = ledPaint.ymin; y <= ledPaint.ymax; ++y) {
+ for (int x = ledPaint.xmin; x <= ledPaint.xmax; ++x) {
+ int color = image.getRGB(x, y);
+ red += (color >> 16) & 0xFF;
+ green += (color >> 8) & 0xFF;
+ blue += color & 0xFF;
+ ++count;
+ }
+ }
+ ledPaint.color = count > 0 ? new Color(red / count, green/count, blue/count).getRGB() : 0;
+
+ ledPaints.add(ledPaint);
+
+ led.lastX = (int) (screenDimension.width * led.led.mLocation.getX());
+ led.lastY = (int) (screenDimension.height * led.led.mLocation.getY());
+
+ ledPaint.screenX = led.lastX;
+ ledPaint.screenY = led.lastY;
+ ledPaint.angle_rad = 0.5*Math.PI - led.led.mSide.getAngle();
+
+ ledPaint.seqNr = led.led.mLedSeqNr;
+ }
+
+ for (int i=2; i<=180; i+=4) {
+ int arcSize = 24 + (int)((i/12.0)*(i/12.0));
+
+ for(LedPaint led : ledPaints) {
+ int argb = 0x05000000 | (0x00ffffff & led.color);
+ g2d.setColor(new Color(argb , true));
+
+ g2d.translate(led.screenX, led.screenY);
+ g2d.rotate(led.angle_rad);
+ g2d.fillArc(-arcSize, -arcSize, 2*arcSize, 2*arcSize, 90-(i/2), i);
+ g2d.rotate(-led.angle_rad);
+ g2d.translate(-led.screenX, -led.screenY);
+ }
+ }
+ }
+
+ private void paintLedNumbers(Graphics2D pG2d) {
+ pG2d.setColor(Color.GRAY);
+
+ FontMetrics fontMetrics = pG2d.getFontMetrics();
+ for (LedWrapper led : mLeds2) {
+ String seqNrStr = "" + led.led.mLedSeqNr;
+ Rectangle2D rect = fontMetrics.getStringBounds(seqNrStr, pG2d);
+
+ pG2d.drawString("" + led.led.mLedSeqNr, (int)(led.lastX-rect.getWidth()/2), (int)(led.lastY+rect.getHeight()/2-2));
+ }
+ }
+
+ public static void main(String[] pArgs) {
+ JFrame frame = new JFrame();
+ frame.setSize(640, 480);
+ frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+
+ frame.getContentPane().setLayout(new BorderLayout());
+ frame.getContentPane().add(new JHyperionTv());
+
+ frame.setVisible(true);
+ }
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/LedFramePanel.java b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/LedFramePanel.java
new file mode 100644
index 00000000..0197d453
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/LedFramePanel.java
@@ -0,0 +1,219 @@
+package org.hyperion.config.gui;
+
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.GroupLayout;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.hyperion.config.spec.DeviceType;
+import org.hyperion.config.spec.LedFrameConstruction;
+
+public class LedFramePanel extends JPanel {
+
+ private final LedFrameConstruction mLedFrameSpec;
+
+ private JLabel mTypeLabel;
+ private JComboBox mTypeCombo;
+
+ private JLabel mHorizontalCountLabel;
+ private JSpinner mHorizontalCountSpinner;
+ private JLabel mBottomGapCountLabel;
+ private JSpinner mBottomGapCountSpinner;
+
+ private JLabel mVerticalCountLabel;
+ private JSpinner mVerticalCountSpinner;
+
+ private JLabel mTopCornerLabel;
+ private JComboBox mTopCornerCombo;
+ private JLabel mBottomCornerLabel;
+ private JComboBox mBottomCornerCombo;
+
+ private JLabel mDirectionLabel;
+ private JComboBox mDirectionCombo;
+
+ private JLabel mOffsetLabel;
+ private JSpinner mOffsetSpinner;
+
+ public LedFramePanel(LedFrameConstruction ledFrameSpec) {
+ super();
+
+ mLedFrameSpec = ledFrameSpec;
+
+ initialise();
+ }
+
+ private void initialise() {
+ mTypeLabel = new JLabel("LED Type:");
+ mTypeLabel.setPreferredSize(new Dimension(100, 30));
+ mTypeLabel.setMaximumSize(new Dimension(150, 30));
+ add(mTypeLabel);
+ mTypeCombo = new JComboBox<>(DeviceType.values());
+ mTypeCombo.addActionListener(mActionListener);
+ mTypeCombo.setPreferredSize(new Dimension(150, 30));
+ mTypeCombo.setMaximumSize(new Dimension(250, 30));
+ add(mTypeCombo);
+
+ mTopCornerLabel = new JLabel("Led in top corners");
+ mTopCornerLabel.setPreferredSize(new Dimension(100, 30));
+ mTopCornerLabel.setMaximumSize(new Dimension(150, 30));
+ add(mTopCornerLabel);
+ mTopCornerCombo = new JComboBox<>(new Boolean[] {true, false});
+ mTopCornerCombo.addActionListener(mActionListener);
+ mTopCornerCombo.setPreferredSize(new Dimension(150, 30));
+ mTopCornerCombo.setMaximumSize(new Dimension(250, 30));
+ add(mTopCornerCombo);
+
+ mBottomCornerLabel = new JLabel("Led in bottom corners");
+ mBottomCornerLabel.setPreferredSize(new Dimension(100, 30));
+ mBottomCornerLabel.setMaximumSize(new Dimension(150, 30));
+ add(mBottomCornerLabel);
+ mBottomCornerCombo = new JComboBox<>(new Boolean[] {true, false});
+ mBottomCornerCombo.addActionListener(mActionListener);
+ mBottomCornerCombo.setPreferredSize(new Dimension(150, 30));
+ mBottomCornerCombo.setMaximumSize(new Dimension(250, 30));
+ add(mBottomCornerCombo);
+
+ mDirectionLabel = new JLabel("Direction");
+ mDirectionLabel.setPreferredSize(new Dimension(100, 30));
+ mDirectionLabel.setMaximumSize(new Dimension(150, 30));
+ add(mDirectionLabel);
+ mDirectionCombo = new JComboBox<>(LedFrameConstruction.Direction.values());
+ mDirectionCombo.addActionListener(mActionListener);
+ mDirectionCombo.setPreferredSize(new Dimension(150, 30));
+ mDirectionCombo.setMaximumSize(new Dimension(250, 30));
+ add(mDirectionCombo);
+
+ mHorizontalCountLabel = new JLabel("Horizontal #:");
+ mHorizontalCountLabel.setPreferredSize(new Dimension(100, 30));
+ mHorizontalCountLabel.setMaximumSize(new Dimension(150, 30));
+ add(mHorizontalCountLabel);
+ mHorizontalCountSpinner = new JSpinner(new SpinnerNumberModel(mLedFrameSpec.topLedCnt, 0, 1024, 1));
+ mHorizontalCountSpinner.addChangeListener(mChangeListener);
+ mHorizontalCountSpinner.setPreferredSize(new Dimension(150, 30));
+ mHorizontalCountSpinner.setMaximumSize(new Dimension(250, 30));
+ add(mHorizontalCountSpinner);
+
+ mBottomGapCountLabel = new JLabel("Bottom Gap #:");
+ mBottomGapCountLabel.setPreferredSize(new Dimension(100, 30));
+ mBottomGapCountLabel.setMaximumSize(new Dimension(150, 30));
+ add(mBottomGapCountLabel);
+ mBottomGapCountSpinner = new JSpinner(new SpinnerNumberModel(mLedFrameSpec.topLedCnt - mLedFrameSpec.bottomLedCnt, 0, 1024, 1));
+ mBottomGapCountSpinner.addChangeListener(mChangeListener);
+ mBottomGapCountSpinner.setPreferredSize(new Dimension(150, 30));
+ mBottomGapCountSpinner.setMaximumSize(new Dimension(250, 30));
+ add(mBottomGapCountSpinner);
+
+ mVerticalCountLabel = new JLabel("Vertical #:");
+ mVerticalCountLabel.setPreferredSize(new Dimension(100, 30));
+ mVerticalCountLabel.setMaximumSize(new Dimension(150, 30));
+ add(mVerticalCountLabel);
+ mVerticalCountSpinner = new JSpinner(new SpinnerNumberModel(mLedFrameSpec.rightLedCnt, 0, 1024, 1));
+ mVerticalCountSpinner.addChangeListener(mChangeListener);
+ mVerticalCountSpinner.setPreferredSize(new Dimension(150, 30));
+ mVerticalCountSpinner.setMaximumSize(new Dimension(250, 30));
+ add(mVerticalCountSpinner);
+
+ mOffsetLabel = new JLabel("1st LED offset");
+ mOffsetLabel.setPreferredSize(new Dimension(100, 30));
+ mOffsetLabel.setMaximumSize(new Dimension(150, 30));
+ add(mOffsetLabel);
+ mOffsetSpinner = new JSpinner(new SpinnerNumberModel(mLedFrameSpec.firstLedOffset, Integer.MIN_VALUE, Integer.MAX_VALUE, 1));
+ mOffsetSpinner.addChangeListener(mChangeListener);
+ mOffsetSpinner.setPreferredSize(new Dimension(150, 30));
+ mOffsetSpinner.setMaximumSize(new Dimension(250, 30));
+ add(mOffsetSpinner);
+
+ GroupLayout layout = new GroupLayout(this);
+ layout.setAutoCreateGaps(true);
+ setLayout(layout);
+
+ layout.setHorizontalGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mTypeLabel)
+ .addComponent(mDirectionLabel)
+ .addComponent(mTopCornerLabel)
+ .addComponent(mBottomCornerLabel)
+ .addComponent(mHorizontalCountLabel)
+ .addComponent(mBottomGapCountLabel)
+ .addComponent(mVerticalCountLabel)
+ .addComponent(mOffsetLabel))
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mTypeCombo)
+ .addComponent(mDirectionCombo)
+ .addComponent(mTopCornerCombo)
+ .addComponent(mBottomCornerCombo)
+ .addComponent(mHorizontalCountSpinner)
+ .addComponent(mBottomGapCountSpinner)
+ .addComponent(mVerticalCountSpinner)
+ .addComponent(mOffsetSpinner))
+ );
+ layout.setVerticalGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mTypeLabel)
+ .addComponent(mTypeCombo))
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mDirectionLabel)
+ .addComponent(mDirectionCombo))
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mTopCornerLabel)
+ .addComponent(mTopCornerCombo))
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mBottomCornerLabel)
+ .addComponent(mBottomCornerCombo))
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mHorizontalCountLabel)
+ .addComponent(mHorizontalCountSpinner))
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mVerticalCountLabel)
+ .addComponent(mVerticalCountSpinner))
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mBottomGapCountLabel)
+ .addComponent(mBottomGapCountSpinner))
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mOffsetLabel)
+ .addComponent(mOffsetSpinner)));
+
+ }
+
+ void updateLedConstruction() {
+ mLedFrameSpec.topLeftCorner = (Boolean)mTopCornerCombo.getSelectedItem();
+ mLedFrameSpec.topRightCorner = (Boolean)mTopCornerCombo.getSelectedItem();
+ mLedFrameSpec.bottomLeftCorner = (Boolean)mBottomCornerCombo.getSelectedItem();
+ mLedFrameSpec.bottomRightCorner = (Boolean)mBottomCornerCombo.getSelectedItem();
+
+ mLedFrameSpec.clockwiseDirection = ((LedFrameConstruction.Direction)mDirectionCombo.getSelectedItem()) == LedFrameConstruction.Direction.clockwise;
+ mLedFrameSpec.firstLedOffset = (Integer)mOffsetSpinner.getValue();
+
+ mLedFrameSpec.topLedCnt = (Integer)mHorizontalCountSpinner.getValue();
+ mLedFrameSpec.bottomLedCnt = Math.max(0, mLedFrameSpec.topLedCnt - (Integer)mBottomGapCountSpinner.getValue());
+ mLedFrameSpec.rightLedCnt = (Integer)mVerticalCountSpinner.getValue();
+ mLedFrameSpec.leftLedCnt = (Integer)mVerticalCountSpinner.getValue();
+
+ mLedFrameSpec.setChanged();
+ mLedFrameSpec.notifyObservers();
+
+ mBottomGapCountSpinner.setValue(mLedFrameSpec.topLedCnt - mLedFrameSpec.bottomLedCnt);
+ }
+
+ private final ActionListener mActionListener = new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ updateLedConstruction();
+ }
+ };
+ private final ChangeListener mChangeListener = new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ updateLedConstruction();
+ }
+ };
+
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/MiscConfigPanel.java b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/MiscConfigPanel.java
new file mode 100644
index 00000000..5146b62c
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/MiscConfigPanel.java
@@ -0,0 +1,142 @@
+package org.hyperion.config.gui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.GroupLayout;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.hyperion.config.spec.BootSequence;
+
+public class MiscConfigPanel extends JPanel {
+
+ private JLabel mMenuLabel;
+ private JComboBox mMenuCombo;
+ private JLabel mVideoLabel;
+ private JComboBox mVideoCombo;
+ private JLabel mPictureLabel;
+ private JComboBox mPictureCombo;
+ private JLabel mAudioLabel;
+ private JComboBox mAudioCombo;
+
+ private JLabel mBlackborderDetectorLabel;
+ private JComboBox mBlackborderDetectorCombo;
+ private JLabel mBootSequenceLabel;
+ private JComboBox mBootSequenceCombo;
+
+ public MiscConfigPanel() {
+ super();
+
+ initialise();
+ }
+
+ private void initialise() {
+ GroupLayout layout = new GroupLayout(this);
+ layout.setAutoCreateGaps(true);
+ setLayout(layout);
+
+ mMenuLabel = new JLabel("XBMC Menu");
+ add(mMenuLabel);
+
+ mMenuCombo = new JComboBox<>(new String[] {"On", "Off"});
+ mMenuCombo.setSelectedItem("Off");
+ mMenuCombo.setToolTipText("Enables('On') or disbales('Off') the ambi-light in the XBMC Menu");
+ mMenuCombo.addActionListener(mActionListener);
+ add(mMenuCombo);
+
+ mVideoLabel = new JLabel("Video");
+ add(mVideoLabel);
+
+ mVideoCombo = new JComboBox<>(new String[] {"On", "Off"});
+ mVideoCombo.setSelectedItem("On");
+ mVideoCombo.setToolTipText("Enables('On') or disbales('Off') the ambi-light during video playback");
+ mVideoCombo.addActionListener(mActionListener);
+ add(mVideoCombo);
+
+ mPictureLabel = new JLabel("Picture");
+ add(mPictureLabel);
+
+ mPictureCombo = new JComboBox<>(new String[] {"On", "Off"});
+ mPictureCombo.setSelectedItem("Off");
+ mPictureCombo.setToolTipText("Enables('On') or disbales('Off') the ambi-light when viewing pictures");
+ mPictureCombo.addActionListener(mActionListener);
+ add(mPictureCombo);
+
+ mAudioLabel = new JLabel("Audio");
+ add(mAudioLabel);
+
+ mAudioCombo = new JComboBox<>(new String[] {"On", "Off"});
+ mAudioCombo.setSelectedItem("Off");
+ mAudioCombo.setToolTipText("Enables('On') or disbales('Off') the ambi-light when listing to audio");
+ mAudioCombo.addActionListener(mActionListener);
+ add(mAudioCombo);
+
+ mBlackborderDetectorLabel = new JLabel("Blackborder Detector:");
+ add(mBlackborderDetectorLabel);
+
+ mBlackborderDetectorCombo = new JComboBox<>(new String[] {"On", "Off"});
+ mBlackborderDetectorCombo.setSelectedItem("On");
+ mBlackborderDetectorCombo.setToolTipText("Enables or disables the blackborder detection and removal");
+ add(mBlackborderDetectorCombo);
+
+ mBootSequenceLabel = new JLabel("Boot Sequence:");
+ add(mBootSequenceLabel);
+
+ mBootSequenceCombo = new JComboBox<>(BootSequence.values());
+ mBootSequenceCombo.setSelectedItem(BootSequence.rainbow);
+ mBootSequenceCombo.setToolTipText("The sequence used on startup to verify proper working of all the leds");
+ add(mBootSequenceCombo);
+
+ layout.setHorizontalGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mMenuLabel)
+ .addComponent(mVideoLabel)
+ .addComponent(mPictureLabel)
+ .addComponent(mAudioLabel)
+ .addComponent(mBlackborderDetectorLabel)
+ .addComponent(mBootSequenceLabel)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mMenuCombo)
+ .addComponent(mVideoCombo)
+ .addComponent(mPictureCombo)
+ .addComponent(mAudioCombo)
+ .addComponent(mBlackborderDetectorCombo)
+ .addComponent(mBootSequenceCombo)
+ ));
+ layout.setVerticalGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mMenuLabel)
+ .addComponent(mMenuCombo)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mVideoLabel)
+ .addComponent(mVideoCombo)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mPictureLabel)
+ .addComponent(mPictureCombo)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mAudioLabel)
+ .addComponent(mAudioCombo)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mBlackborderDetectorLabel)
+ .addComponent(mBlackborderDetectorCombo)
+ )
+ .addGroup(layout.createParallelGroup()
+ .addComponent(mBootSequenceLabel)
+ .addComponent(mBootSequenceCombo)
+ ));
+ }
+
+ private final ActionListener mActionListener = new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+
+ }
+ };
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImageBBB_01.png.REMOVED.git-id b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImageBBB_01.png.REMOVED.git-id
new file mode 100644
index 00000000..ca813483
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImageBBB_01.png.REMOVED.git-id
@@ -0,0 +1 @@
+176f5c8e4a406929620764b19e77c5120570325c
\ No newline at end of file
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImageBBB_02.png.REMOVED.git-id b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImageBBB_02.png.REMOVED.git-id
new file mode 100644
index 00000000..b3f62ec5
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImageBBB_02.png.REMOVED.git-id
@@ -0,0 +1 @@
+048b062d931b7754a533734a1dec21692bce2dc6
\ No newline at end of file
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImageBBB_03.png.REMOVED.git-id b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImageBBB_03.png.REMOVED.git-id
new file mode 100644
index 00000000..5f5afb77
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImageBBB_03.png.REMOVED.git-id
@@ -0,0 +1 @@
+bd23dc9ed11283d527effc78e437e8ef18903123
\ No newline at end of file
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_01.png.REMOVED.git-id b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_01.png.REMOVED.git-id
new file mode 100644
index 00000000..202fe705
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_01.png.REMOVED.git-id
@@ -0,0 +1 @@
+427d6ffe9935a3011f05b13bcf44a47796e99a80
\ No newline at end of file
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_02.png.REMOVED.git-id b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_02.png.REMOVED.git-id
new file mode 100644
index 00000000..4d26fccf
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_02.png.REMOVED.git-id
@@ -0,0 +1 @@
+0dd04b5ec932aa251136740c6ea87f71847eb537
\ No newline at end of file
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_03.png.REMOVED.git-id b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_03.png.REMOVED.git-id
new file mode 100644
index 00000000..bad5b106
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_03.png.REMOVED.git-id
@@ -0,0 +1 @@
+10fa576b5a494b9e0377e8b944904bfa7ac97cb6
\ No newline at end of file
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_04.png b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_04.png
new file mode 100644
index 00000000..6106e5fa
Binary files /dev/null and b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_04.png differ
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_05.png.REMOVED.git-id b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_05.png.REMOVED.git-id
new file mode 100644
index 00000000..e388ef7e
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/gui/TestImage_05.png.REMOVED.git-id
@@ -0,0 +1 @@
+620cf4f8a4c8dc62cabe9045c1ad04c38cecb942
\ No newline at end of file
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/spec/BootSequence.java b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/BootSequence.java
new file mode 100644
index 00000000..805eb576
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/BootSequence.java
@@ -0,0 +1,29 @@
+package org.hyperion.config.spec;
+
+public enum BootSequence {
+ rainbow,
+ knight_rider,
+ none;
+
+ public static BootSequence fromString(String pStr) {
+ for (BootSequence seq : values()) {
+ if (seq.toString().equalsIgnoreCase(pStr)) {
+ return seq;
+ }
+ }
+ return none;
+ }
+
+ @Override
+ public String toString() {
+ switch(this) {
+ case rainbow:
+ return "Rainbow";
+ case knight_rider:
+ return "Kinght Rider";
+ case none:
+ return "None";
+ }
+ return "None";
+ }
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/spec/BorderSide.java b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/BorderSide.java
new file mode 100644
index 00000000..a0bd5675
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/BorderSide.java
@@ -0,0 +1,22 @@
+package org.hyperion.config.spec;
+
+public enum BorderSide {
+ top_left (0.75*Math.PI),
+ top(0.5*Math.PI),
+ top_right(0.25*Math.PI),
+ right(0.0*Math.PI),
+ bottom_right(-0.25*Math.PI),
+ bottom(-0.5*Math.PI),
+ bottom_left(-0.75*Math.PI),
+ left(1.0*Math.PI);
+
+ private final double mAngle;
+
+ BorderSide(double pAngle) {
+ mAngle = pAngle;
+ }
+
+ public double getAngle() {
+ return mAngle;
+ }
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/spec/ColorConfig.java b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/ColorConfig.java
new file mode 100644
index 00000000..0df65857
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/ColorConfig.java
@@ -0,0 +1,77 @@
+package org.hyperion.config.spec;
+
+import java.util.Locale;
+
+public class ColorConfig {
+
+ double mSaturationGain = 1.0;
+ double mValueGain = 1.0;
+
+ double mRedThreshold = 0.0;
+ double mRedGamma = 1.0;
+ double mRedBlacklevel = 0.0;
+ double mRedWhitelevel = 1.0;
+
+ double mGreenThreshold = 0.0;
+ double mGreenGamma = 1.0;
+ double mGreenBlacklevel = 0.0;
+ double mGreenWhitelevel = 1.0;
+
+ double mBlueThreshold = 0.0;
+ double mBlueGamma = 1.0;
+ double mBlueBlacklevel = 0.0;
+ double mBlueWhitelevel = 1.0;
+
+ public String toJsonString() {
+ StringBuffer strBuf = new StringBuffer();
+ strBuf.append("\t\"color\" :\n");
+ strBuf.append("\t{\n");
+ strBuf.append(hsvToJsonString() + ",\n");
+ strBuf.append(rgbToJsonString() + "\n");
+ strBuf.append("\t}");
+
+ return strBuf.toString();
+ }
+
+ public String hsvToJsonString() {
+ StringBuffer strBuf = new StringBuffer();
+ strBuf.append("\t\t\"hsv\" :\n");
+ strBuf.append("\t\t{\n");
+ strBuf.append(String.format(Locale.ROOT, "\t\t\tsaturationGain : %.4f,\n", mSaturationGain));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\tsaturationGain : %.4f\n", mValueGain));
+
+ strBuf.append("\t\t}");
+ return strBuf.toString();
+ }
+
+ public String rgbToJsonString() {
+ StringBuffer strBuf = new StringBuffer();
+
+ strBuf.append("\t\t\"red\" :\n");
+ strBuf.append("\t\t{\n");
+ strBuf.append(String.format(Locale.ROOT, "\t\t\tthreshold : %.4f,\n", mRedThreshold));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\tgamma : %.4f,\n", mRedGamma));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\tblacklevel : %.4f,\n", mRedBlacklevel));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\twhitelevel : %.4f\n", mRedWhitelevel));
+ strBuf.append("\t\t},\n");
+
+ strBuf.append("\t\t\"green\" :\n");
+ strBuf.append("\t\t{\n");
+ strBuf.append(String.format(Locale.ROOT, "\t\t\tthreshold : %.4f,\n", mGreenThreshold));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\tgamma : %.4f,\n", mGreenGamma));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\tblacklevel : %.4f,\n", mGreenBlacklevel));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\twhitelevel : %.4f\n", mGreenWhitelevel));
+ strBuf.append("\t\t},\n");
+
+ strBuf.append("\t\t\"blue\" :\n");
+ strBuf.append("\t\t{\n");
+ strBuf.append(String.format(Locale.ROOT, "\t\t\tthreshold : %.4f,\n", mBlueThreshold));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\tgamma : %.4f,\n", mBlueGamma));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\tblacklevel : %.4f,\n", mBlueBlacklevel));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\twhitelevel : %.4f\n", mBlueWhitelevel));
+ strBuf.append("\t\t}");
+
+ return strBuf.toString();
+ }
+
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/spec/DeviceConfig.java b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/DeviceConfig.java
new file mode 100644
index 00000000..a04e4c17
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/DeviceConfig.java
@@ -0,0 +1,25 @@
+package org.hyperion.config.spec;
+
+public class DeviceConfig {
+
+ String mName = "MyPi";
+ DeviceType mType = DeviceType.ws2801;
+ String mOutput = "/dev/spidev0.0";
+ int mBaudrate = 48000;
+
+ public String toJsonString() {
+ StringBuffer strBuf = new StringBuffer();
+ strBuf.append("\t\"device\" :\n");
+ strBuf.append("\t{\n");
+
+ strBuf.append("\t\t\"name\" : \"").append(mName).append("\",\n");
+ strBuf.append("\t\t\"type\" : \"").append(mType).append("\",\n");
+ strBuf.append("\t\t\"output\" : \"").append(mOutput).append("\",\n");
+ strBuf.append("\t\t\"rate\" : ").append(mBaudrate).append("\n");
+
+ strBuf.append("\t}");
+
+ return strBuf.toString();
+ }
+
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/spec/DeviceType.java b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/DeviceType.java
new file mode 100644
index 00000000..f3cfa8ee
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/DeviceType.java
@@ -0,0 +1,9 @@
+package org.hyperion.config.spec;
+
+public enum DeviceType {
+ ws2801,
+ test,
+ none;
+
+
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/spec/Led.java b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/Led.java
new file mode 100644
index 00000000..8135b3fc
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/Led.java
@@ -0,0 +1,21 @@
+package org.hyperion.config.spec;
+
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+
+public class Led {
+
+ public int mLedSeqNr;
+
+ public BorderSide mSide;
+
+ public Point2D mLocation;
+
+ public Rectangle2D mImageRectangle;
+
+ @Override
+ public String toString() {
+ return "Led[" + mLedSeqNr + "] Location=" + mLocation + " Rectangle=" + mImageRectangle;
+ }
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/spec/LedFrameConstruction.java b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/LedFrameConstruction.java
new file mode 100644
index 00000000..8adc320c
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/LedFrameConstruction.java
@@ -0,0 +1,69 @@
+package org.hyperion.config.spec;
+
+import java.util.Observable;
+
+
+
+/**
+ * The LedFrame describes the construction of leds along the sides of the TV screen.
+ *
+ */
+public class LedFrameConstruction extends Observable {
+
+ public enum Direction {
+ clockwise,
+ counter_clockwise;
+ }
+
+ /** True if the leds are organised clockwise else false (counter clockwise) */
+ public boolean clockwiseDirection;
+
+ /** True if the top left corner has a led else false */
+ public boolean topLeftCorner;
+ /** True if the top right corner has a led else false */
+ public boolean topRightCorner;
+ /** True if the bottom left corner has a led else false */
+ public boolean bottomLeftCorner;
+ /** True if the bottom right corner has a led else false */
+ public boolean bottomRightCorner;
+
+ /** The number of leds between the top-left corner and the top-right corner of the screen
+ (excluding the corner leds) */
+ public int topLedCnt;
+ /** The number of leds between the bottom-left corner and the bottom-right corner of the screen
+ (excluding the corner leds) */
+ public int bottomLedCnt;
+
+ /** The number of leds between the top-left corner and the bottom-left corner of the screen
+ (excluding the corner leds) */
+ public int leftLedCnt;
+ /** The number of leds between the top-right corner and the bottom-right corner of the screen
+ (excluding the corner leds) */
+ public int rightLedCnt;
+
+ /** The offset (in leds) of the starting led counted clockwise from the top-left corner */
+ public int firstLedOffset;
+
+ /** The 'integration depth' of the leds along the horizontal axis of the tv */
+ public double horizontalDepth = 0.05;
+ /** The 'integration depth' of the leds along the vertical axis of the tv */
+ public double verticalDepth = 0.05;
+
+ /** The fraction of overlap from one to another led */
+ public double overlapFraction = 0.0;
+
+ public int getLedCount() {
+ int cornerLedCnt = 0;
+ if (topLeftCorner) ++cornerLedCnt;
+ if (topRightCorner) ++cornerLedCnt;
+ if (bottomLeftCorner) ++cornerLedCnt;
+ if (bottomRightCorner) ++cornerLedCnt;
+
+ return topLedCnt + bottomLedCnt + leftLedCnt + rightLedCnt + cornerLedCnt;
+ }
+
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ }
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/spec/MiscConfig.java b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/MiscConfig.java
new file mode 100644
index 00000000..82e43e78
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/MiscConfig.java
@@ -0,0 +1,46 @@
+package org.hyperion.config.spec;
+
+import java.util.Locale;
+
+
+public class MiscConfig {
+ BootSequence mBootSequence = BootSequence.rainbow;
+ int mBootSequenceLength_ms = 3000;
+
+ boolean mBlackborderDetector = true;
+
+ int mFrameGrabberWidth = 64;
+ int mFrameGrabberHeight = 64;
+ int mFrameGrabberInterval_ms = 100;
+
+ boolean mXbmcChecker = true;
+ String mXbmcAddress = "127.0.0.1";
+ int mXbmcTcpPort = 9090;
+
+ public String toJsonString() {
+ StringBuffer strBuf = new StringBuffer();
+ strBuf.append("\t\"bootsequence\" :\n");
+ strBuf.append("\t{\n");
+ strBuf.append(String.format(Locale.ROOT, "\t\t\"type\" : \"%s\",\n", mBootSequence));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\"duration_ms\" : %d\n", mBootSequenceLength_ms));
+ strBuf.append("\t},\n");
+
+ strBuf.append("\t\"framegrabber\" :\n");
+ strBuf.append("\t{\n");
+ strBuf.append(String.format(Locale.ROOT, "\t\t\"width\" : %d,\n", mFrameGrabberWidth));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\"height\" : %d,\n", mFrameGrabberHeight));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\"frequency_Hz\" : %.1f\n", 1000.0/mFrameGrabberInterval_ms));
+ strBuf.append("\t},\n");
+
+ strBuf.append("\t\"xbmcVideoChecker\" :\n");
+ strBuf.append("\t{\n");
+ strBuf.append(String.format(Locale.ROOT, "\t\t\"enable\" : %s,\n", mXbmcChecker));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\"xbmcAddress\" : \"%s\",\n", mXbmcAddress));
+ strBuf.append(String.format(Locale.ROOT, "\t\t\"xbmcTcpPort\" : %d\n", mXbmcTcpPort));
+ strBuf.append("\t}");
+
+ return strBuf.toString();
+ }
+
+
+}
diff --git a/src/config-tool/ConfigTool/src/org/hyperion/config/spec/Ws2801Led.java b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/Ws2801Led.java
new file mode 100644
index 00000000..ec46f0d6
--- /dev/null
+++ b/src/config-tool/ConfigTool/src/org/hyperion/config/spec/Ws2801Led.java
@@ -0,0 +1,83 @@
+package org.hyperion.config.spec;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+
+import javax.swing.JComponent;
+
+public class Ws2801Led extends JComponent {
+
+ enum Border {
+ top,
+ topleft,
+ left,
+ bottomleft,
+ bottom,
+ bottomright,
+ right,
+ topright;
+ }
+
+ final int size = 12;
+ final int halfSize = size/2;
+
+ final Border mBorder;
+
+ public Ws2801Led(Border pBorder) {
+ mBorder = pBorder;
+ }
+
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ Graphics2D g2d = (Graphics2D) g.create();
+
+// g2d.setColor(Color.BLACK);
+// g2d.drawRect(0, 0, getWidth()-1, getHeight()-1);
+
+ switch (mBorder) {
+ case top:
+ g2d.translate(getWidth()/2, getHeight());
+ break;
+ case topleft:
+ g2d.translate(getWidth(), getHeight());
+ g2d.rotate(1.75*Math.PI);
+ break;
+ case left:
+ g2d.translate(0, getHeight()/2);
+ g2d.rotate(Math.PI*0.5);
+ break;
+ case bottomleft:
+ g2d.translate(getWidth(), 0);
+ g2d.rotate(-0.75*Math.PI);
+ break;
+ case bottom:
+ g2d.translate(getWidth()/2, 0);
+ g2d.rotate(Math.PI*1.0);
+ break;
+ case bottomright:
+ g2d.rotate(0.75*Math.PI);
+ break;
+ case right:
+ g2d.translate(getWidth(), getHeight()/2);
+ g2d.rotate(Math.PI*1.5);
+ break;
+ case topright:
+ g2d.translate(0, getHeight());
+ g2d.rotate(0.25*Math.PI);
+ break;
+ }
+
+ g2d.setColor(new Color(255, 0, 0, 172));
+ g2d.fillRoundRect(-3, -12, 6, 6, 2, 2);
+
+ g2d.setColor(new Color(255, 0, 0, 255));
+ g2d.drawRoundRect(-3, -12, 6, 6, 2, 2);
+
+ g2d.setColor(Color.GRAY);
+ g2d.drawRect(-halfSize, -halfSize, size, halfSize);
+ g2d.fillRect(-halfSize, -halfSize, size, halfSize);
+
+ }
+}