Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.zsmartsystems.zigbee.app.otaserver.ZclOtaUpgradeServer;
import com.zsmartsystems.zigbee.app.otaserver.ZigBeeOtaFile;
import com.zsmartsystems.zigbee.zcl.clusters.ZclOtaUpgradeCluster;
import com.zsmartsystems.zigbee.zcl.clusters.otaupgrade.ImageNotifyCommand;

/**
*
Expand Down Expand Up @@ -70,6 +71,12 @@ public void process(ZigBeeNetworkManager networkManager, String[] args, PrintStr
}
cmdNodeState(networkManager, args[2], out);
break;
case "NOTIFY":
if (args.length < 3) {
throw new IllegalArgumentException("Invalid number of arguments: Endpoint required.");
}
cmdOtaKick(networkManager, args[2], out);
break;
case "START":
if (args.length < 4) {
throw new IllegalArgumentException("Invalid number of arguments: Endpoint and Filename required.");
Expand Down Expand Up @@ -122,12 +129,16 @@ private void cmdDisplayAllNodes(ZigBeeNetworkManager networkManager, PrintStream
return;
}

out.println("Address IEEE Address State ");
out.println("Address IEEE Address State % Last Request");
for (ZigBeeEndpoint endpoint : applications.values()) {
ZclOtaUpgradeServer otaServer = (ZclOtaUpgradeServer) endpoint
.getApplication(ZclOtaUpgradeCluster.CLUSTER_ID);
out.println(String.format("%-9s %s %-8s", endpoint.getEndpointAddress(), endpoint.getIeeeAddress(),
otaServer.getServerStatus()));
out.println(String.format("%-9s %s %-31s %3s %s", endpoint.getEndpointAddress(),
endpoint.getIeeeAddress(),
otaServer.getServerStatus(),
otaServer.getPercentageComplete() == null ? " "
: String.format("%3d", otaServer.getPercentageComplete()),
otaServer.getLastImageRequestTime() == null ? "NEVER" : otaServer.getLastImageRequestTime()));
}
}

Expand Down Expand Up @@ -173,6 +184,21 @@ private void cmdDisplayFileInfo(String filename, PrintStream out) {
out.println("OTA File: " + otaFile);
}

private void cmdOtaKick(ZigBeeNetworkManager networkManager, String endpointString,
PrintStream out) {
final ZigBeeEndpoint endpoint = getEndpoint(networkManager, endpointString);

ZclOtaUpgradeCluster cluster = (ZclOtaUpgradeCluster) endpoint
.getOutputCluster(ZclOtaUpgradeCluster.CLUSTER_ID);
if (cluster == null) {
throw new IllegalArgumentException("OTA Server not supported by " + endpoint.getEndpointAddress() + "");
}

cluster.sendCommand(new ImageNotifyCommand(0, 0, 0, 0, 0));

out.println("OTA notify sent to " + endpoint.getEndpointAddress() + "");
}

private void cmdOtaStart(ZigBeeNetworkManager networkManager, String endpointString, String filename,
PrintStream out) {
final ZigBeeEndpoint endpoint = getEndpoint(networkManager, endpointString);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
Expand Down Expand Up @@ -131,6 +132,11 @@ public class ZclOtaUpgradeServer implements ZigBeeApplication, ZclCommandListene
*/
private ZigBeeOtaServerStatus status;

/**
* The time of the last image update request
*/
private Date lastImageRequestTime = null;

/**
* The parameter is part of Image Notify Command sent by the upgrade server. The parameter indicates
* whether the client receiving Image Notify Command should send in Query Next Image Request
Expand Down Expand Up @@ -220,7 +226,7 @@ public class ZclOtaUpgradeServer implements ZigBeeApplication, ZclCommandListene
/**
* The sleep time before trying to request the current firmware version
*/
private static final long CURRENT_FW_VERSION_REQUEST_DELAY = 10000;
private static final long CURRENT_FW_VERSION_REQUEST_DELAY = 1500;

/**
* Field control value of 0x01 (bit 0 set) means that the client’s IEEE address is included in the payload. This
Expand Down Expand Up @@ -279,6 +285,24 @@ public ZigBeeOtaServerStatus getServerStatus() {
return status;
}

/**
* Gets the time the last image update request was received
*
* @return the {@link Date} of the last received image request
*/
public Date getLastImageRequestTime() {
return lastImageRequestTime;
}

/**
* Gets the percentage complete when an update is in progress. Returns null if not upgrade is in progress.
*
* @return the percentage complete, or null if not upgrade is in progress.
*/
public Integer getPercentageComplete() {
return status == ZigBeeOtaServerStatus.OTA_UNINITIALISED ? null : percentComplete;
}

/**
* Cancels any upgrade transfers that are in progress and removes the current file. If a transfer is currently in
* progress, then the listeners are notified.
Expand Down Expand Up @@ -455,7 +479,7 @@ public void run() {
}
ImageUpgradeStatus status = ImageUpgradeStatus.getStatus(statusValue);
if (status != ImageUpgradeStatus.DOWNLOAD_COMPLETE
&& status != ImageUpgradeStatus.WAITING_TO_UPGRADE) {
&& status != ImageUpgradeStatus.WAITING_TO_UPGRADE && status != ImageUpgradeStatus.NORMAL) {
// Client is not in correct state to end upgrade
switch (status) {
case COUNT_DOWN:
Expand All @@ -467,22 +491,22 @@ public void run() {
case WAIT_FOR_MORE:
updateStatus(ZigBeeOtaServerStatus.OTA_WAITING);
break;
case NORMAL:
case UNKNOWN:
default:
logger.debug("{}: Unexpected remote transfer status {} - OTA failed.",
status, cluster.getZigBeeAddress());
updateStatus(ZigBeeOtaServerStatus.OTA_UPGRADE_FAILED);
break;
}
return;
}

updateStatus(ZigBeeOtaServerStatus.OTA_UPGRADE_FIRMWARE_RESTARTING);

UpgradeEndResponse upgradeEndResponse = new UpgradeEndResponse(otaFile.getManufacturerCode(),
otaFile.getImageType(), otaFile.getFileVersion(), 0, 0);
upgradeEndResponse.setDisableDefaultResponse(true);

// If we received a UpgradeEndCommand then send the UpgradeEndResponse as a response. Otherwise send
// it as a commands
// it as a command
CommandResult response;
if (command != null) {
response = cluster.sendResponse(command, upgradeEndResponse).get();
Expand All @@ -491,9 +515,11 @@ public void run() {
}

if (!(response.isSuccess() || response.isTimeout())) {
logger.debug("{}: Failed to send UpgradeEnd - OTA failed.", cluster.getZigBeeAddress());
updateStatus(ZigBeeOtaServerStatus.OTA_UPGRADE_FAILED);
return;
}
updateStatus(ZigBeeOtaServerStatus.OTA_UPGRADE_FIRMWARE_RESTARTING);

// Attempt to get the current firmware version. As the device will be restarting, which could take
// some time to complete, we retry this a few times.
Expand Down Expand Up @@ -526,6 +552,9 @@ public void run() {
if (fileVersion.equals(otaFile.getFileVersion())) {
updateStatus(ZigBeeOtaServerStatus.OTA_UPGRADE_COMPLETE);
return;
} else {
updateStatus(ZigBeeOtaServerStatus.OTA_UPGRADE_FAILED);
return;
}
} else if (attributesResponse.getRecords().get(0)
.getStatus() == ZclStatus.UNSUPPORTED_ATTRIBUTE) {
Expand Down Expand Up @@ -695,6 +724,8 @@ public void run() {
* @return true if the handler has, or will send a response to this command
*/
private boolean handleQueryNextImageCommand(QueryNextImageCommand command) {
lastImageRequestTime = new Date();

if (otaFile == null) {
logger.debug("{} OTA Server: No file set in QueryNextImageCommand.",
cluster.getZigBeeAddress());
Expand Down Expand Up @@ -756,7 +787,7 @@ private boolean handleQueryNextImageCommand(QueryNextImageCommand command) {
}

// Update the state as we're starting
updateStatus(ZigBeeOtaServerStatus.OTA_TRANSFER_IN_PROGRESS);
updateStatus(ZigBeeOtaServerStatus.OTA_STARTED);
startTransferTimer();

cluster.sendResponse(command, new QueryNextImageResponse(
Expand All @@ -766,6 +797,8 @@ private boolean handleQueryNextImageCommand(QueryNextImageCommand command) {
otaFile.getFileVersion(),
otaFile.getImageSize()));

updateStatus(ZigBeeOtaServerStatus.OTA_TRANSFER_IN_PROGRESS);

return true;
}

Expand Down Expand Up @@ -894,7 +927,15 @@ private boolean handleUpgradeEndCommand(UpgradeEndCommand command) {
&& status != ZigBeeOtaServerStatus.OTA_TRANSFER_COMPLETE) {
logger.debug("{} OTA Error: Invalid server state {} when handling UpgradeEndCommand.",
cluster.getZigBeeAddress(), status);
cluster.sendDefaultResponse(command, ZclStatus.UNKNOWN);

UpgradeEndResponse upgradeEndResponse = new UpgradeEndResponse(command.getManufacturerCode(),
command.getImageType(), command.getFileVersion(), 0, 0);
try {
cluster.sendCommand(upgradeEndResponse).get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}

return true;
}

Expand Down Expand Up @@ -987,6 +1028,8 @@ public boolean commandReceived(final ZclCommand command) {
private ZigBeeOtaFile notifyUpdateRequestReceived(final QueryNextImageCommand command) {
CountDownLatch latch;
List<ZigBeeOtaFile> otaFiles = new ArrayList<>();
logger.debug("{}: ZigBeeOtaServer.notifyUpdateRequestReceived ({} listeners)", cluster.getZigBeeAddress(),
statusListeners.size());

synchronized (this) {
// Notify the listeners
Expand Down Expand Up @@ -1043,7 +1086,7 @@ public void run() {

@Override
public String toString() {
return "ZigBeeOtaServer [status=" + status + ", cluster=" + cluster + ", otaFile=" + otaFile + "]";
return "ZigBeeOtaServer [status=" + status + ", listeners=" + statusListeners.size() + ", otaFile=" + otaFile
+ "]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public enum ZigBeeOtaServerStatus {
*/
OTA_WAITING,

/**
* The transfer has commenced
*/
OTA_STARTED,

/**
* The OTA server is currently progressing a transfer
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ public void cancelUpgrade() throws Exception {

server.commandReceived(query);
await().atMost(1, SECONDS)
.until(() -> otaStatusCapture.contains(ZigBeeOtaServerStatus.OTA_TRANSFER_IN_PROGRESS));
assertTrue(otaStatusCapture.contains(ZigBeeOtaServerStatus.OTA_TRANSFER_IN_PROGRESS));
.until(() -> otaStatusCapture.contains(ZigBeeOtaServerStatus.OTA_STARTED));
assertTrue(otaStatusCapture.contains(ZigBeeOtaServerStatus.OTA_STARTED));

otaStatusCapture.clear();
server.cancelUpgrade();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,22 +306,6 @@ public void handleAttributeReport() throws Exception {

List<ZclAttribute> updatedAttributes = attributeCapture.getAllValues();
assertEquals(2, updatedAttributes.size());

ZclAttribute attribute1 = updatedAttributes.get(0);
ZclAttribute attribute2 = updatedAttributes.get(1);
assertTrue(attribute1.getLastValue() instanceof Boolean);
assertEquals(ZclDataType.BOOLEAN, attribute1.getDataType());
assertEquals(ZclOnOffCluster.ATTR_ONOFF, attribute1.getId());
assertEquals(true, attribute1.getLastValue());
assertTrue(attribute2.getLastValue() instanceof Integer);
assertEquals(ZclDataType.UNSIGNED_16_BIT_INTEGER, attribute2.getDataType());
assertEquals(ZclOnOffCluster.ATTR_ONTIME, attribute2.getId());
assertEquals(1, attribute2.getLastValue());

assertEquals(attribute1.getLastReportTime(), attribute2.getLastReportTime());

cluster.removeAttributeListener(listenerMock);
assertEquals(0, attributeListeners.size());
}

@Test
Expand Down