]> gitweb.hamatoma.de Git - jpinet/commitdiff
GPIO settings can handle output (blinking)
authorhama <hama@siduction.net>
Wed, 13 Jul 2016 21:25:11 +0000 (23:25 +0200)
committerhama <hama@siduction.net>
Wed, 13 Jul 2016 21:25:11 +0000 (23:25 +0200)
src/main/java/de/republib/net/TcpClient.java
src/main/java/de/republib/pinet/Client.java
src/main/java/de/republib/pinet/PinNumber.java
src/main/java/de/republib/pinet/gui/ControlCenter.java
src/main/java/de/republib/pinet/gui/GPIOSettings.java [new file with mode: 0644]
src/main/java/de/republib/util/Announcer.java [new file with mode: 0644]
src/main/java/de/republib/util/DynBytes.java
src/test/java/de/republib/util/DynBytesTest.java

index 705679729e92c0a60e2717a9402c0e880e8c4c79..2e072ce3ec2f784b19b655a838f97947a7bc904e 100644 (file)
@@ -16,13 +16,13 @@ import de.republib.util.DynBytes;
  *
  */
 public class TcpClient {
-       Logger logger = LoggerFactory.getLogger(TcpClient.class);
-       Socket socket = null;
-       DataOutputStream outStream = null;
-       DataInputStream inStream = null;
-       String host = "127.0.0.1";
-       int port;
-       boolean active;
+       private final Logger logger = LoggerFactory.getLogger(TcpClient.class);
+       private Socket socket = null;
+       private DataOutputStream outStream = null;
+       private DataInputStream inStream = null;
+       private String host = "127.0.0.1";
+       private final int port;
+       private boolean active;
 
        /**
         * Constructor.
@@ -49,6 +49,20 @@ public class TcpClient {
                }
        }
 
+       /**
+        * @return the host
+        */
+       public String getHost() {
+               return this.host;
+       }
+
+       /**
+        * @return the port
+        */
+       public int getPort() {
+               return this.port;
+       }
+
        /**
         * Receives a message.
         *
@@ -71,6 +85,19 @@ public class TcpClient {
                return buffer;
        }
 
+       /**
+        * Tests whether the address is the same as a given address.
+        *
+        * @param host
+        *            hostname of the address to compare
+        * @param port
+        *            port of the address to compare
+        * @return
+        */
+       public boolean sameAddress(String host, int port) {
+               return host.equals(this.host) && port == this.port;
+       }
+
        /**
         *
         * @param buffer
index 0dbfea726f7c93e864fdb26354a39e5d2988f9e7..2586eb4550d1d2860afcd50bc0f5c43071d419e5 100644 (file)
@@ -16,9 +16,12 @@ public class Client {
                client.blink(PinNumber.PIN_RPi2_12, 10, 500, 500);
        }
 
-       public static void gui() {
+       /**
+        * Starts the graphical user interface client.
+        */
+       public static void gui(String host, int port) {
                final ControlCenter center = new ControlCenter();
-               center.populate();
+               center.populate(host, port);
                center.run();
        }
 
@@ -40,7 +43,7 @@ public class Client {
                                port = Integer.parseInt(arg);
                        }
                }
-               Client.gui();
+               Client.gui(host, port);
                // Client.client(host, port);
        }
 }
index 09b2260e80c4b6a8f22e4ac9ae8dd0ab74bcabde..bbd7ddc18f29738ebcbc09fcbc67cd27925688ab 100644 (file)
@@ -5,7 +5,7 @@ package de.republib.pinet;
 
 /**
  * Pins of the SystemOnChip BM2835 (used in raspberry pi).
- * 
+ *
  * @author hm
  *
  */
@@ -27,6 +27,8 @@ public enum PinNumber {
        PIN_RPi2_23("RPi2_23", 11), //
        PIN_RPi2_24("RPi2_24", 8), //
        PIN_RPi2_26("RPi2_26", 7), //
+       PIN_RPi2_27("RPi2_27", -1), //
+       PIN_RPi2_28("RPi2_28", -1), //
        PIN_RPi2_29("RPi2_29", 5), //
        PIN_RPi2_31("RPi2_31", 6), //
        PIN_RPi2_32("RPi2_32", 12), //
index 61f7692a81c830f62516ef253d79ed0cc99055f4..df3949ea28f42760bfc2bc04b24c5d30c8419d8d 100644 (file)
@@ -12,6 +12,8 @@ import javax.swing.JTabbedPane;
 import javax.swing.JTextField;
 
 import de.republib.gui.MultiChannelSheet;
+import de.republib.pinet.GpioClient;
+import de.republib.util.Announcer;
 import de.republib.util.FunctionPairData;
 import de.republib.util.I18N;
 import de.republib.util.MathFunction;
@@ -19,10 +21,12 @@ import de.republib.util.MathFunction;
 /**
  * Created by hm on 03.07.16.
  */
-public class ControlCenter {
+public class ControlCenter implements Announcer {
+       private GpioClient client = null;
        private JFrame frame;
+
        private JPanel panelCenter;
-       private JPanel panelOutput;
+       private GPIOSettings panelGPIOSettings;
        private JPanel panelLog;
        private JLabel labelStatusLine;
        private MultiChannelSheet panelData;
@@ -31,7 +35,28 @@ public class ControlCenter {
        private JTextField textFieldPort;
        private JTabbedPane tabbedPane;
 
-       public void populate() {
+       /**
+        * Constructor.
+        */
+       public ControlCenter() {
+
+       }
+
+       /**
+        * @return the client
+        */
+       public GpioClient getClient() {
+               final String host = this.textFieldServer.getText();
+               final String port = this.textFieldPort.getText();
+               final int port2 = port.length() == 0 ? 15000 : Integer.parseInt(port);
+               if (this.client == null || !this.client.sameAddress(host, port2)) {
+                       this.client = new GpioClient(host, port2);
+               }
+
+               return this.client;
+       }
+
+       public void populate(String host, int port) {
                this.frame = new JFrame(I18N.tr("Pinet Control Center"));
                this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
@@ -43,13 +68,19 @@ public class ControlCenter {
                this.frame.add(this.labelStatusLine = new JLabel(I18N.tr("welcome")), BorderLayout.SOUTH);
 
                this.panelHead.add(new JLabel(I18N.tr("Server:")));
-               this.panelHead.add(this.textFieldServer = new JTextField("localhost"));
+               this.panelHead.add(this.textFieldServer = new JTextField(host));
                this.panelHead.add(new JLabel(I18N.tr("Port:")));
-               this.panelHead.add(this.textFieldPort = new JTextField("15000"));
+               this.panelHead.add(this.textFieldPort = new JTextField(String.valueOf(port)));
 
                this.panelCenter.add(this.tabbedPane = new JTabbedPane());
-               this.tabbedPane.addTab(I18N.tr("Output"), this.panelOutput = new JPanel());
+               this.tabbedPane.addTab(I18N.tr("GPIO settings"), this.panelGPIOSettings = new GPIOSettings(this));
+               this.panelGPIOSettings.populate();
                this.tabbedPane.addTab(I18N.tr("Diagram"), this.panelData = new MultiChannelSheet());
+               populateCurves();
+               this.tabbedPane.addTab(I18N.tr("Log"), this.panelLog = new JPanel());
+       }
+
+       private void populateCurves() {
                FunctionPairData function = new FunctionPairData(MathFunction.X, 0.0, 10.0, 790);
                function.setFactor(9.0);
                function.setOffset(1.0);
@@ -70,7 +101,7 @@ public class ControlCenter {
                this.panelData.addChannel(function);
                function = new FunctionPairData(MathFunction.TAN, 0.0, 1.0, 790);
                this.panelData.addChannel(function);
-               this.tabbedPane.addTab(I18N.tr("Log"), this.panelLog = new JPanel());
+
        }
 
        public void run() {
@@ -78,4 +109,28 @@ public class ControlCenter {
                this.frame.pack();
                this.frame.setVisible(true);
        }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see de.republib.util.Announcer#say(int, java.lang.String)
+        */
+       @Override
+       public void say(int level, final String message) {
+               String prefix = null;
+               switch (level) {
+               case Announcer.ERROR:
+                       prefix = "+++ ";
+                       break;
+               case Announcer.WARNING:
+                       prefix = "*** ";
+                       break;
+               default:
+               }
+               if (prefix == null) {
+                       this.labelStatusLine.setText(message);
+               } else {
+                       this.labelStatusLine.setText(prefix + message);
+               }
+       }
 }
diff --git a/src/main/java/de/republib/pinet/gui/GPIOSettings.java b/src/main/java/de/republib/pinet/gui/GPIOSettings.java
new file mode 100644 (file)
index 0000000..812fd18
--- /dev/null
@@ -0,0 +1,362 @@
+/**
+ *
+ */
+package de.republib.pinet.gui;
+
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import de.republib.pinet.GpioClient;
+import de.republib.pinet.PinNumber;
+import de.republib.util.Announcer;
+import de.republib.util.DynBytes;
+import de.republib.util.I18N;
+
+/**
+ * Manages the register page "GPIO Settings".
+ *
+ * @author hm
+ *
+ */
+public class GPIOSettings extends JPanel {
+       /**
+        *
+        */
+       private static final long serialVersionUID = 1L;
+       private GPIOTable gpioTable;
+       private OutputData panelOutputData;
+       private final ControlCenter center;
+
+       /**
+        *
+        * @param center
+        * @return
+        */
+       public GPIOSettings(ControlCenter center) {
+               this.center = center;
+       }
+
+       public void populate() {
+
+               this.gpioTable = new GPIOTable();
+               add(this.gpioTable);
+               final PinData panelPinData = new PinData(this.gpioTable);
+               this.gpioTable.setPanelPinData(panelPinData);
+               add(panelPinData);
+               add(this.panelOutputData = new OutputData(this.center, panelPinData));
+       }
+}
+
+class GPIOTable extends JPanel implements ActionListener {
+       /**
+        *
+        */
+       private static final long serialVersionUID = 1L;
+
+       private final PinButton[] pinButtons = new PinButton[40];
+
+       private final JLabel[] columnNames = { new JLabel(I18N.tr("Name")), new JLabel(I18N.tr("Pin")),
+                       new JLabel(I18N.tr("Pin")), new JLabel(I18N.tr("Name")) };
+
+       private final Object[][] cells;
+       PinData panelPinData;
+
+       /**
+        * Constructor.
+        */
+       public GPIOTable() {
+               super(new GridLayout(21, 4));
+               this.panelPinData = this.panelPinData;
+               this.pinButtons[0] = new PinButton(0, I18N.tr("+3.3V"), null);
+               this.pinButtons[1] = new PinButton(1, I18N.tr("+5V"), null);
+               this.pinButtons[2] = new PinButton(2, "SDA1", PinNumber.PIN_RPi2_03);
+               this.pinButtons[3] = new PinButton(3, I18N.tr("+5V"), null);
+               this.pinButtons[4] = new PinButton(4, "SCL1", PinNumber.PIN_RPi2_05);
+               this.pinButtons[5] = new PinButton(5, I18N.tr("GND"), null);
+               this.pinButtons[6] = new PinButton(6, "GCLK", PinNumber.PIN_RPi2_07);
+               this.pinButtons[7] = new PinButton(7, "TXD0", PinNumber.PIN_RPi2_08);
+               this.pinButtons[8] = new PinButton(8, I18N.tr("GND"), null);
+               this.pinButtons[9] = new PinButton(9, "RXD0", PinNumber.PIN_RPi2_10);
+               this.pinButtons[10] = new PinButton(10, "GEN0", PinNumber.PIN_RPi2_11);
+               this.pinButtons[11] = new PinButton(11, "GEN1", PinNumber.PIN_RPi2_12);
+               this.pinButtons[12] = new PinButton(12, "GEN2", PinNumber.PIN_RPi2_13);
+               this.pinButtons[13] = new PinButton(13, I18N.tr("GND"), null);
+               this.pinButtons[14] = new PinButton(14, "GEN3", PinNumber.PIN_RPi2_15);
+               this.pinButtons[15] = new PinButton(15, "GEN4", PinNumber.PIN_RPi2_16);
+               this.pinButtons[16] = new PinButton(16, I18N.tr("+3.3V"), null);
+               this.pinButtons[17] = new PinButton(17, "GEN5", PinNumber.PIN_RPi2_18);
+               this.pinButtons[18] = new PinButton(18, "SPI_MOSI", PinNumber.PIN_RPi2_19);
+               this.pinButtons[19] = new PinButton(19, I18N.tr("GND"), null);
+               this.pinButtons[20] = new PinButton(20, "SPI_MISO", PinNumber.PIN_RPi2_21);
+               this.pinButtons[21] = new PinButton(21, "GEN6", PinNumber.PIN_RPi2_22);
+               this.pinButtons[22] = new PinButton(22, "SPI_SCLK", PinNumber.PIN_RPi2_23);
+               this.pinButtons[23] = new PinButton(23, "SPI_CE0", PinNumber.PIN_RPi2_24);
+               this.pinButtons[24] = new PinButton(24, I18N.tr("GND"), null);
+               this.pinButtons[25] = new PinButton(25, "SPI_CE1", PinNumber.PIN_RPi2_26);
+               this.pinButtons[26] = new PinButton(26, "I2C_ID_SC", PinNumber.PIN_RPi2_27);
+               this.pinButtons[27] = new PinButton(27, "I2C_ID_SD", PinNumber.PIN_RPi2_28);
+               this.pinButtons[28] = new PinButton(28, null, PinNumber.PIN_RPi2_29);
+               this.pinButtons[29] = new PinButton(29, I18N.tr("GND"), null);
+               this.pinButtons[30] = new PinButton(30, null, PinNumber.PIN_RPi2_31);
+               this.pinButtons[31] = new PinButton(31, null, PinNumber.PIN_RPi2_32);
+               this.pinButtons[32] = new PinButton(32, null, PinNumber.PIN_RPi2_33);
+               this.pinButtons[33] = new PinButton(33, I18N.tr("GND"), null);
+               this.pinButtons[34] = new PinButton(34, null, PinNumber.PIN_RPi2_35);
+               this.pinButtons[35] = new PinButton(35, null, PinNumber.PIN_RPi2_36);
+               this.pinButtons[36] = new PinButton(36, null, PinNumber.PIN_RPi2_37);
+               this.pinButtons[37] = new PinButton(37, null, PinNumber.PIN_RPi2_38);
+               this.pinButtons[38] = new PinButton(38, I18N.tr("GND"), null);
+               this.pinButtons[39] = new PinButton(39, null, PinNumber.PIN_RPi2_40);
+               for (final PinButton pinButton : this.pinButtons) {
+                       pinButton.addActionListener(this);
+               }
+
+               this.cells = new Object[20][4];
+               for (int row = 0; row < 20; row++) {
+                       PinButton button = this.pinButtons[row * 2];
+                       this.cells[row][0] = new JLabel(button.getTitle());
+                       this.cells[row][1] = button;
+                       button = this.pinButtons[row * 2 + 1];
+                       this.cells[row][2] = button;
+                       this.cells[row][3] = new JLabel(button.getTitle());
+               }
+               populate();
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               final PinButton button = (PinButton) e.getSource();
+               this.panelPinData.fillData(button);
+       }
+
+       public Component getCell(int row, int column) {
+               final Component rc = (Component) this.cells[row][column];
+               return rc;
+       }
+
+       /**
+        * @return the pinButtons
+        */
+       public PinButton getPinButton(int index) {
+               return this.pinButtons[index];
+       }
+
+       public void populate() {
+               int col;
+               for (col = 0; col < 4; col++) {
+                       add(this.columnNames[col]);
+               }
+               for (int row = 0; row < 20; row++) {
+                       for (col = 0; col < 4; col++) {
+                               add((Component) this.cells[row][col]);
+                       }
+               }
+       }
+
+       /**
+        * @param panelPinData
+        *            the panelPinData to set
+        */
+       public void setPanelPinData(PinData panelPinData) {
+               this.panelPinData = panelPinData;
+       }
+}
+
+/**
+ * Shows and manages the panel controlling the output behaviour of a pin.
+ *
+ * @author hm
+ *
+ */
+class OutputData extends JPanel implements ActionListener {
+       /**
+        *
+        */
+       private static final long serialVersionUID = 1L;
+
+       private final static String[] modes = { I18N.tr("Blink") };
+       private JComboBox<String> comboMode;
+       private JTextField textCount;
+       private JTextField textHigh;
+       private JTextField textLow;
+       private JButton buttonRun;
+       private final ControlCenter center;
+       private final PinData pinData;
+
+       /**
+        * Constructor.
+        */
+       public OutputData(ControlCenter center, PinData pinData) {
+               super(new GridLayout(0, 2));
+               this.center = center;
+               this.pinData = pinData;
+               add(new JLabel(I18N.tr("Mode:")));
+               add(this.comboMode = new JComboBox<>(OutputData.modes));
+               add(new JLabel(I18N.tr("Count:")));
+               add(this.textCount = new JTextField("10"));
+               add(new JLabel(I18N.tr("High:")));
+               add(this.textHigh = new JTextField("500"));
+               add(new JLabel(I18N.tr("Low:")));
+               add(this.textLow = new JTextField("500"));
+               add(new JLabel(""));
+               add(this.buttonRun = new JButton(I18N.tr("Start")));
+               this.buttonRun.addActionListener(this);
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               final GpioClient client = this.center.getClient();
+               final PinButton current = this.pinData.getCurrentPin();
+               final int count = numberOf(this.textCount, 10);
+               final int high = numberOf(this.textHigh, 500);
+               final int low = numberOf(this.textLow, 500);
+               this.center.say(Announcer.LOG, String.format(I18N.tr("blinking started on pin %d"), current.getPinNumber()));
+               final DynBytes answer = client.blink(current.getPinNumber(), count, high, low);
+               if (answer.startsWith("OK")) {
+                       this.center.say(Announcer.LOG,
+                                       String.format(I18N.tr("pin %d blinks %d times"), current.getPinNumber(), count));
+               }
+       }
+
+       /**
+        * Gets a number from a text field.
+        *
+        * @param text
+        *            the text field
+        * @param defaultValue
+        *            the return value for invalid field values
+        * @return <i>defaultValue</i>: invalid field value<br>
+        *         otherwise: the value of the field as integer
+        */
+       private int numberOf(JTextField text, int defaultValue) {
+               int rc = defaultValue;
+               try {
+                       rc = Integer.parseInt(text.getText());
+               } catch (final NumberFormatException e) {
+                       this.center.say(Announcer.ERROR,
+                                       String.format(I18N.tr("not a number: '%s' used instead: %d"), text.getText(), rc));
+                       text.setText(String.valueOf(rc));
+               }
+               return rc;
+       }
+}
+
+class PinButton extends JButton {
+       /**
+        *
+        */
+       private static final long serialVersionUID = 1L;
+       private final PinNumber pinNumber;
+       private final String title;
+
+       int index;
+
+       /**
+        * Constructor.
+        *
+        * @param title
+        *            <i>null</i>: the title is generated from the
+        *            <i>pinNumber<i><br>
+        *            otherwise: the title of the pin
+        * @param pinNumber
+        *            <i>null</i>: not a IO pin, e.g. ground or +3.3V<br>
+        *            otherwise: the pin number
+        */
+       public PinButton(int index, String title, PinNumber pinNumber) {
+               super(pinNumber == null ? title : String.valueOf(index + 1));
+               this.index = index;
+               this.title = title == null ? pinNumber.getName() : title;
+               this.pinNumber = pinNumber;
+       }
+
+       /**
+        * @return the index
+        */
+       public int getIndex() {
+               return this.index;
+       }
+
+       /**
+        * @return the pinNumber
+        */
+       public PinNumber getPinNumber() {
+               return this.pinNumber;
+       }
+
+       /**
+        * @return the title
+        */
+       public String getTitle() {
+               return this.title;
+       }
+}
+
+/**
+ * Shows and manages the data of the current pin in a panel.
+ *
+ * @author hm
+ *
+ */
+class PinData extends JPanel {
+       /**
+        *
+        */
+       private static final long serialVersionUID = 1L;
+       private JLabel labelPin;
+       private JLabel labelInternalNo;
+       private JLabel labelTitle;
+       private JComboBox<String> comboMode;
+       private final String[] modes = { I18N.tr("undefined"), I18N.tr("input"), I18N.tr("output") };
+       private PinButton currentPin = null;
+
+       /**
+        * Constructor.
+        *
+        * @param table
+        *            info about the pins
+        */
+       public PinData(GPIOTable table) {
+               super(new GridLayout(0, 2));
+               add(new JLabel(I18N.tr("Pin No:")));
+               add(this.labelPin = new JLabel());
+               add(new JLabel(I18N.tr("GPIO number:")));
+               add(this.labelInternalNo = new JLabel());
+               add(new JLabel(I18N.tr("Title:")));
+               add(this.labelTitle = new JLabel());
+               add(new JLabel(I18N.tr("Mode:")));
+               add(this.comboMode = new JComboBox<>(this.modes));
+               add(new JLabel());
+               fillData(table.getPinButton(11));
+       }
+
+       /**
+        * Fills the data of the panel from the current pin.
+        *
+        * @param button
+        *            properties of the pin
+        */
+       public void fillData(PinButton button) {
+               this.currentPin = button;
+               final PinNumber number = button.getPinNumber();
+               this.labelPin.setText(String.valueOf(button.getIndex() + 1));
+               this.labelInternalNo.setText(number == null ? "-" : String.valueOf(number.getNumber()));
+               this.labelTitle.setText(button.getTitle());
+               this.comboMode.setVisible(number != null);
+               this.comboMode.setSelectedIndex(0);
+       }
+
+       /**
+        * @return the currentPin
+        */
+       public PinButton getCurrentPin() {
+               return this.currentPin;
+       }
+}
\ No newline at end of file
diff --git a/src/main/java/de/republib/util/Announcer.java b/src/main/java/de/republib/util/Announcer.java
new file mode 100644 (file)
index 0000000..8993314
--- /dev/null
@@ -0,0 +1,17 @@
+/**
+ *
+ */
+package de.republib.util;
+
+/**
+ * @author hm
+ *
+ */
+public interface Announcer {
+       final int ERROR = 1;
+       final int WARNING = 2;
+       final int LOG = 3;
+       final int DEBUG = 4;
+
+       void say(int level, String message);
+}
index d01cfaafe86260189d14814ca08610e14014f454..eb3edcd498b42d398d36b0c667b87f395300b565 100644 (file)
@@ -195,6 +195,45 @@ public class DynBytes {
                return this;
        }
 
+       /**
+        * Compares the instance with a given byte sequence.
+        *
+        * @param value
+        *            value to compare
+        * @param from
+        *            first index of <i>value</i>to compare.<br>
+        *            Set to 0 if &lt; 0
+        * @param from2
+        *            first index of <i>this.buffer</i>to compare.<br>
+        *            Set to 0 if &lt; 0
+        * @param length
+        *            number of bytes to compare
+        * @return <i>&lt; 0</i>: value &lt; instance<br>
+        *         <i>0</i>: value == instance<br>
+        *         <i>&gt; 0</i>: value &gt; instance<br>
+        */
+       public int compare(byte[] value, int from, int from2, int length) {
+               int rc = 0;
+               if (from < 0) {
+                       from = 0;
+               }
+               if (from2 < 0) {
+                       from2 = 0;
+               }
+               final int maxLength = Math.max(value.length - from, this.length - from2);
+               if (length > maxLength) {
+                       length = maxLength;
+               }
+               while (rc == 0 && length > 0 && from < value.length && from2 < this.length) {
+                       rc = this.buffer[from2++] - value[from++];
+                       length--;
+               }
+               if (rc == 0 && length != 0) {
+                       rc = from < value.length ? -1 : from2 < this.length ? 1 : -1;
+               }
+               return rc;
+       }
+
        /**
         * Ensures that the size of the buffer is larger or equal to a given size.
         * <p>
@@ -361,10 +400,29 @@ public class DynBytes {
                return this;
        }
 
+       /**
+        * Tests whether a buffer starts with a given string.
+        *
+        * @param prefix
+        *            string to test
+        * @return <i>true</i>: the instance starts with the given string
+        */
+       public boolean startsWith(String prefix) {
+               byte[] value;
+               boolean rc = false;
+               try {
+                       value = prefix.getBytes("UTF-8");
+                       rc = compare(value, 0, 0, value.length) == 0;
+               } catch (final UnsupportedEncodingException e) {
+                       DynBytes.logger.error("cannot convert from UTF-8", e);
+               }
+               return rc;
+       }
+
        /**
         * Converts the content into an UTF-8 string.
         *
-        * @return <i>null</i>: not convertable<br>
+        * @return <i>null</i>: not convertible<br>
         *         otherwise: the content as UTF-8 string
         */
        public String toUtf8() {
@@ -392,7 +450,11 @@ public class DynBytes {
                } else {
                        try {
                                final int length = Math.min(this.length, maxLength);
-                               rc = new String(this.buffer, 0, length, "UTF-8");
+                               if (length <= 0) {
+                                       rc = "";
+                               } else {
+                                       rc = new String(this.buffer, 0, length, "UTF-8");
+                               }
                        } catch (final UnsupportedEncodingException e) {
                                DynBytes.logger.error("DynBytes.toUtf8(): ", e);
                        }
index 4e6e3f8fc131fa05b7abc7ad8a607ba1a1b4a7d2..e0dadd0d772f9fbe1ac576cf366fd8956ecbe889 100644 (file)
@@ -89,6 +89,47 @@ public class DynBytesTest {
                Assert.assertEquals(buffer.getBlocksize(), 17);
        }
 
+       @org.testng.annotations.Test
+       public void testCompare() throws Exception {
+               final DynBytes buffer = new DynBytes(16, 16);
+               buffer.append((byte) 0x41).append((byte) 0x31).append((byte) 0x61);
+               final byte[] buffer2 = { 0x41, 0x31, 0x61 };
+               // buffer == buffer2
+               Assert.assertEquals(buffer.compare(buffer2, 0, 0, 1), 0);
+               Assert.assertEquals(buffer.compare(buffer2, 0, 0, 2), 0);
+               Assert.assertEquals(buffer.compare(buffer2, 0, 0, 3), 0);
+               Assert.assertEquals(buffer.compare(buffer2, 0, 0, 4), 0);
+               // buffer < buffer2
+               Assert.assertEquals(buffer.compare(buffer2, 0, 1, 1), -0x10);
+               Assert.assertEquals(buffer.compare(buffer2, 0, 1, 2), -0x10);
+               // buffer > buffer2
+               Assert.assertEquals(buffer.compare(buffer2, 1, 0, 1), 0x10);
+               Assert.assertEquals(buffer.compare(buffer2, 1, 0, 2), 0x10);
+               // different length:
+               final byte[] buffer3 = { 0x41, 0x31 };
+               // buffer > buffer3
+               Assert.assertEquals(buffer.compare(buffer3, 0, 0, 4), 1);
+               Assert.assertEquals(buffer.compare(buffer3, 1, 1, 4), 1);
+               final byte[] buffer4 = { 0x41, 0x31, 0x61, 0x62 };
+               // buffer < buffer4
+               Assert.assertEquals(buffer.compare(buffer4, 0, 0, 4), -1);
+               Assert.assertEquals(buffer.compare(buffer4, 1, 1, 4), -1);
+               Assert.assertEquals(buffer.compare(buffer4, 2, 2, 4), -1);
+
+               // wrong indexes:
+               // too large in value:
+               Assert.assertEquals(buffer.compare(buffer2, 3, 0, 2), -1);
+               // too large in buffer:
+               Assert.assertEquals(buffer.compare(buffer2, 0, 4, 2), 1);
+               // both too large:
+               Assert.assertEquals(buffer.compare(buffer2, 3, 4, 2), 0);
+
+               // to small in value:
+               Assert.assertEquals(buffer.compare(buffer2, -1, 0, 2), -1);
+               // too small in buffer:
+               Assert.assertEquals(buffer.compare(buffer2, 4, -1, 2), 1);
+       }
+
        @org.testng.annotations.Test
        public void testEnsureSize() throws Exception {
                final DynBytes buffer = new DynBytes(2, 2);