diff --git a/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/driver/Port.java b/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/driver/Port.java index 3b5653b7e3f16..9b2c24e4bcac9 100644 --- a/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/driver/Port.java +++ b/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/driver/Port.java @@ -300,21 +300,23 @@ public void run() { } private void processMessages() { - try { - // must call processData() until we get a null pointer back - for (Msg m = msgFactory.processData(); m != null; m = msgFactory.processData()) { - toAllListeners(m); - notifyWriter(m); - } - } catch (IOException e) { - // got bad data from modem, - // unblock those waiting for ack - logger.warn("bad data received: {}", e.getMessage()); - synchronized (getRequestReplyLock()) { - if (reply == ReplyType.WAITING_FOR_ACK) { - logger.warn("got bad data back, must assume message was acked."); - reply = ReplyType.GOT_ACK; - getRequestReplyLock().notify(); + // must call processData() until msgFactory done fully processing buffer + while (!msgFactory.isDone()) { + try { + Msg msg = msgFactory.processData(); + if (msg != null) { + toAllListeners(msg); + notifyWriter(msg); + } + } catch (IOException e) { + // got bad data from modem, + // unblock those waiting for ack + synchronized (getRequestReplyLock()) { + if (reply == ReplyType.WAITING_FOR_ACK) { + logger.debug("got bad data back, must assume message was acked."); + reply = ReplyType.GOT_ACK; + getRequestReplyLock().notify(); + } } } } diff --git a/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/driver/hub/HubIOStream.java b/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/driver/hub/HubIOStream.java index fd08382283455..144eb3cfd839e 100644 --- a/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/driver/hub/HubIOStream.java +++ b/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/driver/hub/HubIOStream.java @@ -23,6 +23,7 @@ import java.nio.charset.StandardCharsets; import java.util.Base64; +import org.apache.commons.lang.StringUtils; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.insteon.internal.driver.IOStream; @@ -159,6 +160,7 @@ private synchronized String bufferStatus() throws IOException { * @throws IOException */ private synchronized void clearBuffer() throws IOException { + logger.trace("clearing buffer"); getURL("/1?XB=M=1"); bufferIdx = 0; } @@ -171,14 +173,15 @@ private synchronized void clearBuffer() throws IOException { */ public synchronized void write(ByteBuffer msg) throws IOException { poll(); // fetch the status buffer before we send out commands - clearBuffer(); // clear the status buffer explicitly. StringBuilder b = new StringBuilder(); while (msg.remaining() > 0) { b.append(String.format("%02x", msg.get())); } String hexMSG = b.toString(); + logger.trace("writing a message"); getURL("/3?" + hexMSG + "=I=3"); + bufferIdx = 0; } /** @@ -210,10 +213,22 @@ public synchronized void poll() throws IOException { return; // XXX why return here???? } + if (StringUtils.repeat("0", data.length()).equals(data)) { + logger.trace("skip cleared buffer"); + bufferIdx = 0; + return; + } + StringBuilder msg = new StringBuilder(); if (nIdx < bufferIdx) { - msg.append(data.substring(bufferIdx, data.length())); - msg.append(data.substring(0, nIdx)); + String msgStart = data.substring(bufferIdx, data.length()); + String msgEnd = data.substring(0, nIdx); + if (StringUtils.repeat("0", msgStart.length()).equals(msgStart)) { + logger.trace("discard cleared buffer wrap around msg start"); + msgStart = ""; + } + + msg.append(msgStart + msgEnd); logger.trace("wrap around: copying new data on: {}", msg.toString()); } else { msg.append(data.substring(bufferIdx, nIdx)); @@ -278,8 +293,6 @@ private String getData(InputStream is) throws IOException { } String s = baos.toString(); - logger.trace("read:\n{}", s); - return s; } finally { bis.close(); diff --git a/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/message/MsgFactory.java b/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/message/MsgFactory.java index 2a9a4859edc50..26fd5a737f11b 100644 --- a/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/message/MsgFactory.java +++ b/bundles/org.openhab.binding.insteon/src/main/java/org/openhab/binding/insteon/internal/message/MsgFactory.java @@ -40,6 +40,7 @@ public class MsgFactory { private static final int MAX_MSG_LEN = 4096; private byte[] buf = new byte[MAX_MSG_LEN]; private int end = 0; // offset of end of buffer + private boolean done = true; // done fully processing buffer flag /** * Constructor @@ -47,6 +48,15 @@ public class MsgFactory { public MsgFactory() { } + /** + * Indicates if no more complete message available in the buffer to be processed + * + * @return buffer data fully processed flag + */ + public boolean isDone() { + return done; + } + /** * Adds incoming data to the data buffer. First call addData(), then call processData() * @@ -56,9 +66,13 @@ public MsgFactory() { public void addData(byte[] data, int len) { int l = len; if (l + end > MAX_MSG_LEN) { - logger.warn("warn: truncating excessively long message!"); + logger.warn("truncating excessively long message!"); l = MAX_MSG_LEN - end; } + // indicate new data can be processed if length > 0 + if (l > 0) { + done = false; + } // append the new data to the one we already have System.arraycopy(data, 0, buf, end, l); end += l; @@ -75,13 +89,14 @@ public void addData(byte[] data, int len) { * @throws IOException if data was received with unknown command codes */ public @Nullable Msg processData() throws IOException { + Msg msg = null; // handle the case where we get a pure nack if (end > 0 && buf[0] == 0x15) { logger.trace("got pure nack!"); removeFromBuffer(1); try { - Msg m = Msg.makeMessage("PureNACK"); - return m; + msg = Msg.makeMessage("PureNACK"); + return msg; } catch (InvalidMessageTypeException e) { return null; } @@ -93,36 +108,40 @@ public void addData(byte[] data, int len) { // Now see if we have enough data for a complete message. // If not, we return null, and expect this method to be called again // when more data has come in. - int msgLen = -1; - boolean isExtended = false; if (end > 1) { // we have some data, but do we have enough to read the entire header? int headerLength = Msg.getHeaderLength(buf[1]); - isExtended = Msg.isExtended(buf, end, headerLength); + boolean isExtended = Msg.isExtended(buf, end, headerLength); logger.trace("header length expected: {} extended: {}", headerLength, isExtended); if (headerLength < 0) { removeFromBuffer(1); // get rid of the leading 0x02 so draining works - bail("got unknown command code " + Utils.getHexByte(buf[1])); + bail("got unknown command code " + Utils.getHexByte(buf[0])); } else if (headerLength >= 2) { if (end >= headerLength) { // only when the header is complete do we know that isExtended is correct! - msgLen = Msg.getMessageLength(buf[1], isExtended); + int msgLen = Msg.getMessageLength(buf[1], isExtended); + logger.trace("msgLen expected: {}", msgLen); if (msgLen < 0) { // Cannot make sense out of the combined command code & isExtended flag. removeFromBuffer(1); - bail("unknown command code/ext flag: " + Utils.getHexByte(buf[1])); + bail("got unknown command code/ext flag " + Utils.getHexByte(buf[0])); + } else if (msgLen > 0) { + if (end >= msgLen) { + msg = Msg.createMessage(buf, msgLen, isExtended); + removeFromBuffer(msgLen); + } + } else { // should never happen + logger.warn("invalid message length, internal error!"); } } } else { // should never happen logger.warn("invalid header length, internal error!"); - msgLen = -1; } } - logger.trace("msgLen expected: {}", msgLen); - Msg msg = null; - if (msgLen > 0 && end >= msgLen) { - msg = Msg.createMessage(buf, msgLen, isExtended); - removeFromBuffer(msgLen); + // indicate no more messages available in buffer if empty or undefined message + if (end == 0 || msg == null) { + logger.trace("done processing current buffer data"); + done = true; } logger.trace("keeping buffer len {} data: {}", end, Utils.getHexString(buf, end)); return msg; @@ -130,7 +149,7 @@ public void addData(byte[] data, int len) { private void bail(String txt) throws IOException { drainBuffer(); // this will drain until end or it finds the next 0x02 - logger.warn("{}", txt); + logger.debug("bad data received: {}", txt); throw new IOException(txt); } diff --git a/bundles/org.openhab.binding.insteon/src/main/resources/msg_definitions.xml b/bundles/org.openhab.binding.insteon/src/main/resources/msg_definitions.xml index 50aa493113ad5..d4c1cf08aeff2 100644 --- a/bundles/org.openhab.binding.insteon/src/main/resources/msg_definitions.xml +++ b/bundles/org.openhab.binding.insteon/src/main/resources/msg_definitions.xml @@ -120,6 +120,17 @@ + +
+ 0x02 + 0x5c +
+
+ +
+ + +
@@ -281,7 +292,7 @@
- +
@@ -396,4 +407,4 @@ - \ No newline at end of file +