Skip to content

Commit c798801

Browse files
wsowacdjackson
authored andcommitted
Fix updating transaction state for (near to) fragmented frames (#940)
Signed-off-by: Witold Sowa <[email protected]>
1 parent facac54 commit c798801

File tree

4 files changed

+114
-8
lines changed

4 files changed

+114
-8
lines changed

com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/ZigBeeNetworkManager.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1901,9 +1901,9 @@ public Future<CommandResult> sendTransaction(ZigBeeCommand command, ZigBeeTransa
19011901
@Override
19021902
public void receiveCommandState(int msgTag, ZigBeeTransportProgressState state) {
19031903
logger.debug("RX STA: msgTag={} state={}", String.format("%02X", msgTag), state);
1904-
if (apsDataEntity.receiveCommandState(msgTag, state) == false) {
1905-
return;
1904+
if (apsDataEntity.receiveCommandState(msgTag, state)) {
1905+
// Pass the update to the transaction if this is NACK or ACK for last/only fragment
1906+
transactionManager.receiveCommandState(msgTag, state);
19061907
}
1907-
transactionManager.receiveCommandState(msgTag, state);
19081908
}
19091909
}

com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/aps/ApsDataEntity.java

+14-5
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public synchronized boolean send(final int msgTag, final ZigBeeApsFrame apsFrame
164164

165165
// Check that we have fragmentation enabled and that this frame requires fragmenting
166166
// TODO: Don't fragment unicast or broadcast
167-
if (apsFrame.getPayload().length < fragmentationLength || fragmentationWindow == 0) {
167+
if (apsFrame.getPayload().length <= fragmentationLength || fragmentationWindow == 0) {
168168
transport.sendCommand(msgTag, apsFrame);
169169
return true;
170170
}
@@ -225,7 +225,7 @@ private void sendNextFragments(final ZigBeeApsFrame apsFrame) {
225225

226226
fragment.setPayload(Arrays.copyOfRange(apsFrame.getPayload(), offset, end));
227227

228-
apsFrame.setFragmentOutstanding(apsFrame.getFragmentOutstanding() + 1);
228+
apsFrame.oneFragmentSent();
229229
logger.debug("Sending APS Frame Fragment: outstanding={} {}", apsFrame.getFragmentOutstanding(), fragment);
230230

231231
transport.sendCommand(apsFrame.getMsgTag(), fragment);
@@ -239,7 +239,7 @@ private void sendNextFragments(final ZigBeeApsFrame apsFrame) {
239239
*
240240
* @param msgTag the message tag whose state is updated
241241
* @param state the updated ZigBeeTransportProgressState for the transaction
242-
* @return false if this frame is part of a fragmented packet and this is not the last frame. true otherwise.
242+
* @return true if this last frame in packet or not fragmented frame. false otherwise.
243243
*/
244244
public boolean receiveCommandState(int msgTag, ZigBeeTransportProgressState state) {
245245
ZigBeeApsFrame outgoingFrame = getFragmentedFrameFromQueue(msgTag);
@@ -258,8 +258,17 @@ public boolean receiveCommandState(int msgTag, ZigBeeTransportProgressState stat
258258
logger.debug("receiveCommandState tag={}, fragmentBase={}, fragmentOutstanding={}", msgTag,
259259
outgoingFrame.getFragmentBase(), outgoingFrame.getFragmentOutstanding());
260260

261-
outgoingFrame.setFragmentBase(outgoingFrame.getFragmentBase() + 1);
262-
outgoingFrame.setFragmentOutstanding(outgoingFrame.getFragmentOutstanding() - 1);
261+
// TX ACK doesn't mean the frame was delivered so it should be ignored.
262+
if (state == ZigBeeTransportProgressState.RX_ACK) {
263+
outgoingFrame.oneFragmentCompleted();
264+
}
265+
266+
if (state == ZigBeeTransportProgressState.TX_ACK &&
267+
outgoingFrame.getFragmentBase() + 1 == outgoingFrame.getFragmentTotal()) {
268+
logger.debug("TX ACKed for last block in frame: {}", outgoingFrame);
269+
return true;
270+
}
271+
263272
if (outgoingFrame.getFragmentBase() == outgoingFrame.getFragmentTotal()) {
264273
logger.debug("Completed Sending Fragment APS Frame: {}", outgoingFrame);
265274
return true;

com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/aps/ZigBeeApsFrame.java

+19
Original file line numberDiff line numberDiff line change
@@ -426,4 +426,23 @@ public String toString() {
426426
return builder.toString();
427427
}
428428

429+
/**
430+
* Calling this method indicates that transmission of a fragment has completed.
431+
* It moves the fragment base and decrease outstanding fragments counter.
432+
*/
433+
public void oneFragmentCompleted() {
434+
fragmentBase++;
435+
if (fragmentOutstanding > 0) {
436+
fragmentOutstanding--;
437+
}
438+
}
439+
440+
/**
441+
* Calling this method indicates that a fragment has been sent. It increases outstanding fragments counter.
442+
*/
443+
public void oneFragmentSent() {
444+
if (fragmentOutstanding <= fragmentTotal) {
445+
this.fragmentOutstanding++;
446+
}
447+
}
429448
}

com.zsmartsystems.zigbee/src/test/java/com/zsmartsystems/zigbee/aps/ApsDataEntityTest.java

+78
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
*
2828
*/
2929
public class ApsDataEntityTest {
30+
public static final int FRAGMENTATION_LENGTH = 65;
3031
private static int TIMEOUT = 5000;
3132

3233
@Test
@@ -226,6 +227,83 @@ public void receiveCommandState() {
226227
assertTrue(aps.receiveCommandState(0, ZigBeeTransportProgressState.RX_ACK));
227228
}
228229

230+
@Test
231+
public void shouldExpectOneFrameReceivedForPayloadShorterThanFragmentationLength() {
232+
ZigBeeTransportTransmit transport = Mockito.mock(ZigBeeTransportTransmit.class);
233+
ApsDataEntity aps = new ApsDataEntity(transport);
234+
235+
aps.setFragmentationLength(FRAGMENTATION_LENGTH);
236+
237+
ZigBeeApsFrame apsFrame = new ZigBeeApsFrame();
238+
apsFrame.setApsCounter(1);
239+
apsFrame.setPayload(createData(0, FRAGMENTATION_LENGTH-1));
240+
241+
aps.send(0, apsFrame);
242+
243+
assertTrue(aps.receiveCommandState(0, ZigBeeTransportProgressState.TX_ACK));
244+
assertTrue(aps.receiveCommandState(0, ZigBeeTransportProgressState.RX_ACK));
245+
}
246+
247+
@Test
248+
public void shouldExpectOneFrameReceivedForPayloadEqualToFragmentationLength() {
249+
ZigBeeTransportTransmit transport = Mockito.mock(ZigBeeTransportTransmit.class);
250+
ApsDataEntity aps = new ApsDataEntity(transport);
251+
252+
aps.setFragmentationLength(FRAGMENTATION_LENGTH);
253+
254+
ZigBeeApsFrame apsFrame = new ZigBeeApsFrame();
255+
apsFrame.setApsCounter(1);
256+
apsFrame.setPayload(createData(0, FRAGMENTATION_LENGTH));
257+
258+
aps.send(0, apsFrame);
259+
260+
assertTrue(aps.receiveCommandState(0, ZigBeeTransportProgressState.TX_ACK));
261+
assertTrue(aps.receiveCommandState(0, ZigBeeTransportProgressState.RX_ACK));
262+
}
263+
264+
@Test
265+
public void shouldExpectTwoFramesReceivedForPayloadFittingInTwoFragments() {
266+
ZigBeeTransportTransmit transport = Mockito.mock(ZigBeeTransportTransmit.class);
267+
ApsDataEntity aps = new ApsDataEntity(transport);
268+
269+
aps.setFragmentationLength(FRAGMENTATION_LENGTH);
270+
271+
ZigBeeApsFrame apsFrame = new ZigBeeApsFrame();
272+
apsFrame.setApsCounter(1);
273+
apsFrame.setPayload(createData(0, FRAGMENTATION_LENGTH+1));
274+
275+
aps.send(0, apsFrame);
276+
277+
assertFalse(aps.receiveCommandState(0, ZigBeeTransportProgressState.TX_ACK));
278+
assertFalse(aps.receiveCommandState(0, ZigBeeTransportProgressState.RX_ACK));
279+
280+
assertTrue(aps.receiveCommandState(0, ZigBeeTransportProgressState.TX_ACK));
281+
assertTrue(aps.receiveCommandState(0, ZigBeeTransportProgressState.RX_ACK));
282+
}
283+
284+
@Test
285+
public void shouldExpectThreeFramesReceivedForPayloadFittingInThreeFragments() {
286+
ZigBeeTransportTransmit transport = Mockito.mock(ZigBeeTransportTransmit.class);
287+
ApsDataEntity aps = new ApsDataEntity(transport);
288+
289+
aps.setFragmentationLength(FRAGMENTATION_LENGTH);
290+
291+
ZigBeeApsFrame apsFrame = new ZigBeeApsFrame();
292+
apsFrame.setApsCounter(1);
293+
apsFrame.setPayload(createData(0, FRAGMENTATION_LENGTH*2+1));
294+
295+
aps.send(0, apsFrame);
296+
297+
assertFalse(aps.receiveCommandState(0, ZigBeeTransportProgressState.TX_ACK));
298+
assertFalse(aps.receiveCommandState(0, ZigBeeTransportProgressState.RX_ACK));
299+
300+
assertFalse(aps.receiveCommandState(0, ZigBeeTransportProgressState.TX_ACK));
301+
assertFalse(aps.receiveCommandState(0, ZigBeeTransportProgressState.RX_ACK));
302+
303+
assertTrue(aps.receiveCommandState(0, ZigBeeTransportProgressState.TX_ACK));
304+
assertTrue(aps.receiveCommandState(0, ZigBeeTransportProgressState.RX_ACK));
305+
}
306+
229307
private int[] createData(int start, int length) {
230308
int[] data = new int[length];
231309

0 commit comments

Comments
 (0)