diff --git a/xbee-api/src/main/java/com/homeclimatecontrol/xbee/FrameIdGenerator.java b/xbee-api/src/main/java/com/homeclimatecontrol/xbee/FrameIdGenerator.java new file mode 100644 index 0000000..dfc25bc --- /dev/null +++ b/xbee-api/src/main/java/com/homeclimatecontrol/xbee/FrameIdGenerator.java @@ -0,0 +1,34 @@ +package com.homeclimatecontrol.xbee; + +import com.rapplogic.xbee.api.XBeeRequest; + +/** + * A singleton to generate a packet frame ID. + */ +public class FrameIdGenerator { + + private static final byte MAX_ID = (byte) 0xFF; + + private byte currentId = MAX_ID; + + private static final FrameIdGenerator instance = new FrameIdGenerator(); + + public static FrameIdGenerator getInstance() { + return instance; + } + + public synchronized void reset() { + currentId = MAX_ID; + } + + public synchronized byte getNext() { + + if (currentId == MAX_ID) { + // Can't be 0 or we won't get the response + // Also, skip the tainted DEFAULT_FRAME_ID to avoid the warning + currentId = XBeeRequest.DEFAULT_FRAME_ID; + } + + return ++currentId; + } +} diff --git a/xbee-api/src/main/java/com/rapplogic/xbee/api/AtCommand.java b/xbee-api/src/main/java/com/rapplogic/xbee/api/AtCommand.java index d4ef162..8620279 100644 --- a/xbee-api/src/main/java/com/rapplogic/xbee/api/AtCommand.java +++ b/xbee-api/src/main/java/com/rapplogic/xbee/api/AtCommand.java @@ -19,6 +19,7 @@ package com.rapplogic.xbee.api; +import com.homeclimatecontrol.xbee.FrameIdGenerator; import com.rapplogic.xbee.util.ByteUtils; import com.rapplogic.xbee.util.IntArrayOutputStream; @@ -122,15 +123,15 @@ public enum Command { // } public AtCommand(Command command) { - this(command, null, DEFAULT_FRAME_ID); + this(command, null, FrameIdGenerator.getInstance().getNext()); } public AtCommand(Command command, int value) { - this(command, new int[]{value}, DEFAULT_FRAME_ID); + this(command, new int[]{value}, FrameIdGenerator.getInstance().getNext()); } public AtCommand(Command command, int[] value) { - this(command, value, DEFAULT_FRAME_ID); + this(command, value, FrameIdGenerator.getInstance().getNext()); } /** diff --git a/xbee-api/src/main/java/com/rapplogic/xbee/api/AtCommandQueue.java b/xbee-api/src/main/java/com/rapplogic/xbee/api/AtCommandQueue.java index b72b03e..d556dff 100644 --- a/xbee-api/src/main/java/com/rapplogic/xbee/api/AtCommandQueue.java +++ b/xbee-api/src/main/java/com/rapplogic/xbee/api/AtCommandQueue.java @@ -19,6 +19,8 @@ package com.rapplogic.xbee.api; +import com.homeclimatecontrol.xbee.FrameIdGenerator; + /** * AT Command Queue *
@@ -30,7 +32,7 @@ public class AtCommandQueue extends AtCommand { //TODO test public AtCommandQueue(Command command) { - this(command, null, DEFAULT_FRAME_ID); + this(command, null, FrameIdGenerator.getInstance().getNext()); } public AtCommandQueue(Command command, int[] value, byte frameId) { diff --git a/xbee-api/src/main/java/com/rapplogic/xbee/api/RemoteAtRequest.java b/xbee-api/src/main/java/com/rapplogic/xbee/api/RemoteAtRequest.java index 9a29563..61d1bc9 100644 --- a/xbee-api/src/main/java/com/rapplogic/xbee/api/RemoteAtRequest.java +++ b/xbee-api/src/main/java/com/rapplogic/xbee/api/RemoteAtRequest.java @@ -19,6 +19,7 @@ package com.rapplogic.xbee.api; +import com.homeclimatecontrol.xbee.FrameIdGenerator; import com.rapplogic.xbee.util.IntArrayOutputStream; /** @@ -71,20 +72,20 @@ public RemoteAtRequest(byte frameId, XBeeAddress64 remoteAddress64, XBeeAddress1 /** * Abbreviated Constructor for setting an AT command on a remote XBee. - * This defaults to the DEFAULT_FRAME_ID, and true for apply changes + * This defaults to {@link FrameIdGenerator#getNext()} and {@code true} for "apply changes". */ public RemoteAtRequest(XBeeAddress64 dest64, Command command, int[] value) { // Note: the ZNET broadcast also works for series 1. We could also use ffff but then that wouldn't work for series 2 - this(XBeeRequest.DEFAULT_FRAME_ID, dest64, XBeeAddress16.ZNET_BROADCAST, true, command, value); + this(FrameIdGenerator.getInstance().getNext(), dest64, XBeeAddress16.ZNET_BROADCAST, true, command, value); } public RemoteAtRequest(XBeeAddress64 dest64, Command command, int value) { - this(XBeeRequest.DEFAULT_FRAME_ID, dest64, XBeeAddress16.ZNET_BROADCAST, true, command, new int[]{value}); + this(FrameIdGenerator.getInstance().getNext(), dest64, XBeeAddress16.ZNET_BROADCAST, true, command, new int[]{value}); } /** * Abbreviated Constructor for querying the value of an AT command on a remote XBee. - * This defaults to the DEFAULT_FRAME_ID, and false for apply changes + * This defaults to {@link FrameIdGenerator#getNext()} and {@code false} for "apply changes". */ public RemoteAtRequest(XBeeAddress64 dest64, Command command) { this(dest64, command, null); @@ -108,14 +109,14 @@ public RemoteAtRequest(XBeeAddress16 dest16, Command command) { * Creates a Remote AT instance for setting the value of an AT command on a remote XBee, * by specifying the 16-bit address and value. Uses the broadcast address for 64-bit address (00 00 00 00 00 00 ff ff) * - * Defaults are: frame id: 1, applyChanges: true + * Defaults are: {@link FrameIdGenerator#getNext()}, applyChanges: true */ public RemoteAtRequest(XBeeAddress16 remoteAddress16, Command command, int[] value) { - this(XBeeRequest.DEFAULT_FRAME_ID, XBeeAddress64.BROADCAST, remoteAddress16, true, command, value); + this(FrameIdGenerator.getInstance().getNext(), XBeeAddress64.BROADCAST, remoteAddress16, true, command, value); } public RemoteAtRequest(XBeeAddress16 remoteAddress16, Command command, int value) { - this(XBeeRequest.DEFAULT_FRAME_ID, XBeeAddress64.BROADCAST, remoteAddress16, true, command, new int[]{value}); + this(FrameIdGenerator.getInstance().getNext(), XBeeAddress64.BROADCAST, remoteAddress16, true, command, new int[]{value}); } @Override diff --git a/xbee-api/src/main/java/com/rapplogic/xbee/api/wpan/TxRequest16.java b/xbee-api/src/main/java/com/rapplogic/xbee/api/wpan/TxRequest16.java index bea429d..84506e6 100644 --- a/xbee-api/src/main/java/com/rapplogic/xbee/api/wpan/TxRequest16.java +++ b/xbee-api/src/main/java/com/rapplogic/xbee/api/wpan/TxRequest16.java @@ -19,6 +19,7 @@ package com.rapplogic.xbee.api.wpan; +import com.homeclimatecontrol.xbee.FrameIdGenerator; import com.rapplogic.xbee.api.ApiId; import com.rapplogic.xbee.api.XBeeAddress16; import com.rapplogic.xbee.util.IntArrayOutputStream; @@ -43,7 +44,7 @@ public class TxRequest16 extends TxRequestBase { * hex, so if you set MY=1234, use 0x1234. */ public TxRequest16(XBeeAddress16 remoteAddr16, int[] payload) { - this(remoteAddr16, DEFAULT_FRAME_ID, Option.UNICAST, payload); + this(remoteAddr16, FrameIdGenerator.getInstance().getNext(), Option.UNICAST, payload); } /** diff --git a/xbee-api/src/main/java/com/rapplogic/xbee/api/wpan/TxRequest64.java b/xbee-api/src/main/java/com/rapplogic/xbee/api/wpan/TxRequest64.java index fe39be0..54c9e9f 100644 --- a/xbee-api/src/main/java/com/rapplogic/xbee/api/wpan/TxRequest64.java +++ b/xbee-api/src/main/java/com/rapplogic/xbee/api/wpan/TxRequest64.java @@ -19,6 +19,7 @@ package com.rapplogic.xbee.api.wpan; +import com.homeclimatecontrol.xbee.FrameIdGenerator; import com.rapplogic.xbee.api.ApiId; import com.rapplogic.xbee.api.XBeeAddress64; import com.rapplogic.xbee.util.IntArrayOutputStream; @@ -47,7 +48,7 @@ public class TxRequest64 extends TxRequestBase { * 16 bit Tx Request with default frame id and awk option */ public TxRequest64(XBeeAddress64 destination, int[] payload) { - this(destination, DEFAULT_FRAME_ID, Option.UNICAST, payload); + this(destination, FrameIdGenerator.getInstance().getNext(), Option.UNICAST, payload); } /** diff --git a/xbee-api/src/main/java/com/rapplogic/xbee/api/zigbee/ZBForceSampleRequest.java b/xbee-api/src/main/java/com/rapplogic/xbee/api/zigbee/ZBForceSampleRequest.java index be4a759..7cf22fa 100644 --- a/xbee-api/src/main/java/com/rapplogic/xbee/api/zigbee/ZBForceSampleRequest.java +++ b/xbee-api/src/main/java/com/rapplogic/xbee/api/zigbee/ZBForceSampleRequest.java @@ -19,10 +19,10 @@ package com.rapplogic.xbee.api.zigbee; +import com.homeclimatecontrol.xbee.FrameIdGenerator; import com.rapplogic.xbee.api.RemoteAtRequest; import com.rapplogic.xbee.api.XBeeAddress16; import com.rapplogic.xbee.api.XBeeAddress64; -import com.rapplogic.xbee.api.XBeeRequest; import static com.rapplogic.xbee.api.AtCommand.Command.IS; @@ -38,6 +38,6 @@ public class ZBForceSampleRequest extends RemoteAtRequest { * Creates a Force Sample Remote AT request */ public ZBForceSampleRequest(XBeeAddress64 dest64) { - super(XBeeRequest.DEFAULT_FRAME_ID, dest64, XBeeAddress16.ZNET_BROADCAST, false, IS, null); + super(FrameIdGenerator.getInstance().getNext(), dest64, XBeeAddress16.ZNET_BROADCAST, false, IS, null); } } diff --git a/xbee-api/src/main/java/com/rapplogic/xbee/api/zigbee/ZNetTxRequest.java b/xbee-api/src/main/java/com/rapplogic/xbee/api/zigbee/ZNetTxRequest.java index c20a8a6..1fbb9fb 100644 --- a/xbee-api/src/main/java/com/rapplogic/xbee/api/zigbee/ZNetTxRequest.java +++ b/xbee-api/src/main/java/com/rapplogic/xbee/api/zigbee/ZNetTxRequest.java @@ -19,6 +19,7 @@ package com.rapplogic.xbee.api.zigbee; +import com.homeclimatecontrol.xbee.FrameIdGenerator; import com.rapplogic.xbee.api.ApiId; import com.rapplogic.xbee.api.XBeeAddress16; import com.rapplogic.xbee.api.XBeeAddress64; @@ -129,7 +130,7 @@ public ZNetTxRequest(byte frameId, XBeeAddress64 dest64, XBeeAddress16 dest16, i * Abbreviated constructor for sending a unicast TX packet. */ public ZNetTxRequest(XBeeAddress64 dest64, int[] payload) { - this(XBeeRequest.DEFAULT_FRAME_ID, dest64, XBeeAddress16.ZNET_BROADCAST, ZNetTxRequest.DEFAULT_BROADCAST_RADIUS, Option.UNICAST, payload); + this(FrameIdGenerator.getInstance().getNext(), dest64, XBeeAddress16.ZNET_BROADCAST, ZNetTxRequest.DEFAULT_BROADCAST_RADIUS, Option.UNICAST, payload); } /** diff --git a/xbee-api/src/test/java/com/homeclimatecontrol/xbee/FrameIdGeneratorTest.java b/xbee-api/src/test/java/com/homeclimatecontrol/xbee/FrameIdGeneratorTest.java new file mode 100644 index 0000000..e2fe2cc --- /dev/null +++ b/xbee-api/src/test/java/com/homeclimatecontrol/xbee/FrameIdGeneratorTest.java @@ -0,0 +1,24 @@ +package com.homeclimatecontrol.xbee; + +import com.rapplogic.xbee.api.XBeeRequest; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class FrameIdGeneratorTest { + + /** + * Make sure we never get zero, or {@link com.rapplogic.xbee.api.XBeeRequest#DEFAULT_FRAME_ID}. + */ + @Test + void rollOverTest() { + + for (int i = 0; i < 0xFF * 4; i++) { + + var id = FrameIdGenerator.getInstance().getNext(); + + assertThat(id).isNotZero(); + assertThat(id).isNotEqualTo(XBeeRequest.DEFAULT_FRAME_ID); + } + } +} diff --git a/xbee-api/src/test/java/com/homeclimatecontrol/xbee/XbeeApiTest.java b/xbee-api/src/test/java/com/homeclimatecontrol/xbee/XbeeApiTest.java index 24d0661..4146d83 100644 --- a/xbee-api/src/test/java/com/homeclimatecontrol/xbee/XbeeApiTest.java +++ b/xbee-api/src/test/java/com/homeclimatecontrol/xbee/XbeeApiTest.java @@ -2,8 +2,10 @@ import com.rapplogic.xbee.api.AtCommand; import com.rapplogic.xbee.api.RemoteAtRequest; +import com.rapplogic.xbee.api.XBeeAddress16; import com.rapplogic.xbee.api.XBeeAddress64; import com.rapplogic.xbee.api.XBeePacket; +import com.rapplogic.xbee.api.XBeeRequest; import com.rapplogic.xbee.util.ByteUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -50,7 +52,7 @@ class XbeeApiTest { @Test void packetEscape() { - final int[] knownGoodPacket = new int[]{ + int[] knownGoodPacket = new int[]{ 0x7E, // Start delimiter 0x00, // Length MSB 0x0F, // Length LSB @@ -78,7 +80,7 @@ void packetEscape() { try { XBeeAddress64 xbeeAddress = AddressParser.parse("0013A200.4062AC98"); - RemoteAtRequest request = new RemoteAtRequest(xbeeAddress, D0); + RemoteAtRequest request = new RemoteAtRequest(XBeeRequest.DEFAULT_FRAME_ID, xbeeAddress, XBeeAddress16.ZNET_BROADCAST, true, D0, null); request.setApplyChanges(true);