(context.dataTypes.values());
- dataTypes.addAll(context.dataTypes.values());
-
- generateZclDataTypeEnumeration(dataTypes, packageRoot, packageFile);
- } catch (final IOException e) {
- System.out.println("Failed to generate data types enumeration.");
- e.printStackTrace();
- return;
- }
-
- try {
- generateZclProfileTypeEnumeration(context, packageRoot, packageFile);
- } catch (final IOException e) {
- System.out.println("Failed to generate profile enumeration.");
- e.printStackTrace();
- return;
- }
-
- try {
- generateZclClusterTypeEnumeration(context, packageRoot, packageFile);
- } catch (final IOException e) {
- System.out.println("Failed to generate cluster enumeration.");
- e.printStackTrace();
- return;
- }
-
- try {
- // generateZclCommandTypeEnumerationXXXXX(context, packageRoot, packageFile);
- generateZclCommandTypeEnumeration(context, packageRoot, packageFile);
- } catch (final IOException e) {
- System.out.println("Failed to generate command enumeration.");
- e.printStackTrace();
- return;
- }
-
- try {
- generateAttributeEnumeration(context, packageRoot, sourceRootPath);
- } catch (final IOException e) {
- System.out.println("Failed to generate attribute enum classes.");
- e.printStackTrace();
- return;
- }
-
- try {
- generateFieldEnumeration(context, packageRoot, sourceRootPath);
- } catch (final IOException e) {
- System.out.println("Failed to generate field enum classes.");
- e.printStackTrace();
- return;
- }
-
- try {
- generateZclCommandClasses(context, packageRoot, sourceRootPath);
- } catch (final IOException e) {
- System.out.println("Failed to generate profile message classes.");
- e.printStackTrace();
- return;
- }
-
- try {
- generateZclClusterClasses(context, packageRoot, sourceRootPath);
- } catch (final IOException e) {
- System.out.println("Failed to generate cluster classes.");
- e.printStackTrace();
- return;
- }
- }
-
- public static void generateZdpCode(final Context context, final File sourceRootPath, final String packageRoot) {
- ZclProtocolDefinitionParser.parseProfiles(context);
-
- try {
- generateZdpCommandClasses(context, packageRoot, sourceRootPath);
- } catch (final IOException e) {
- System.out.println("Failed to generate profile message classes.");
- e.printStackTrace();
- return;
- }
-
- try {
- generateZdoCommandTypeEnumeration(context, packageRoot, sourceRootPath);
- } catch (final IOException e) {
- System.out.println("Failed to generate command enumeration.");
- e.printStackTrace();
- return;
- }
-
- }
-
- private static void outputClassJavaDoc(final PrintWriter out, String description) {
- out.println("/**");
- out.println(" * " + description);
- out.println(" * ");
- out.println(" * Code is auto-generated. Modifications may be overwritten!");
- out.println(" *");
- out.println(" * @author Chris Jackson");
- out.println(" */");
- }
-
- private static File getPackageFile(String packagePath) {
- final File packageFile = new File(packagePath);
- if (!packageFile.exists()) {
- packageFile.mkdirs();
- }
- return packageFile;
- }
-
- private static String getPackagePath(File sourceRootPath, String packageRoot) {
- return sourceRootPath.getAbsolutePath() + File.separator + packageRoot.replace(".", File.separator);
- }
-
- private static void generateZclDataTypeEnumeration(LinkedList dataTypes, final String packageRootPrefix,
- File sourceRootPath) throws IOException {
- final String className = "ZclDataType";
-
- final String packageRoot = packageRootPrefix + packageZclProtocol;
- final String packagePath = getPackagePath(sourceRootPath, packageZclProtocol);
- final File packageFile = getPackageFile(packagePath);
-
- final PrintWriter out = getClassOut(packageFile, className);
- CodeGeneratorUtil.outputLicense(out);
-
- out.println("package " + packageRoot + ";");
-
- out.println();
- out.println("import java.util.Calendar;");
- out.println("import java.util.HashMap;");
- out.println("import java.util.Map;");
- out.println();
- out.println("import javax.annotation.Generated;");
- out.println("import " + packageRootPrefix + packageZclField + ".*;");
- out.println("import " + packageRootPrefix + packageZcl + ".ZclStatus;");
- out.println("import " + packageRootPrefix + packageZdp + ".ZdoStatus;");
- out.println("import " + packageRootPrefix + packageZdpDescriptors + ".*;");
- out.println("import " + packageRootPrefix + "." + "IeeeAddress" + ";");
- out.println("import " + packageRootPrefix + "." + "ExtendedPanId" + ";");
- out.println();
- outputClassJavaDoc(out, "Enumeration of the ZCL data types");
- outputClassGenerated(out);
- out.println("public enum " + className + " {");
-
- DataType newDataType = new DataType();
-
- newDataType = new DataType();
- newDataType.dataTypeName = "Unsigned 8 bit Integer Array";
- newDataType.dataTypeType = "UNSIGNED_8_BIT_INTEGER_ARRAY";
- newDataType.dataTypeClass = ZclDataType.getDataTypeMapping().get("UNSIGNED_8_BIT_INTEGER_ARRAY").dataClass;
- dataTypes.add(newDataType);
-
- newDataType = new DataType();
- newDataType.dataTypeName = "ZigBee Data Type";
- newDataType.dataTypeType = "ZIGBEE_DATA_TYPE";
- newDataType.dataTypeClass = ZclDataType.getDataTypeMapping().get("ZIGBEE_DATA_TYPE").dataClass;
- dataTypes.add(newDataType);
-
- // final LinkedList dataTypes = new LinkedList(context.dataTypes.values());
- for (final DataType dataType : dataTypes) {
- DataTypeMap zclDataType = ZclDataType.getDataTypeMapping().get(dataType.dataTypeType);
- final String dataTypeClass;
- if (dataType.dataTypeClass.contains("<")) {
- dataTypeClass = dataType.dataTypeClass.substring(dataType.dataTypeClass.indexOf("<") + 1,
- dataType.dataTypeClass.indexOf(">"));
- } else {
- dataTypeClass = dataType.dataTypeClass;
- }
- out.print(" " + dataType.dataTypeType + "(\"" + dataType.dataTypeName + "\", " + dataTypeClass + ".class"
- + ", " + String.format("0x%02X", zclDataType.id) + ", " + zclDataType.analogue + ")");
- out.println(dataTypes.getLast().equals(dataType) ? ';' : ',');
- }
-
- out.println();
- out.println(" private final String label;");
- out.println(" private final Class> dataClass;");
- out.println(" private final int id;");
- out.println(" private final boolean analogue;");
- out.println(" private static Map codeTypeMapping;");
- out.println();
-
- out.println(" static {");
- out.println(" codeTypeMapping = new HashMap();");
- out.println(" for (" + className + " s : values()) {");
- out.println(" codeTypeMapping.put(s.id, s);");
- out.println(" }");
- out.println(" }");
- out.println();
- out.println(" " + className
- + "(final String label, final Class> dataClass, final int id, final boolean analogue) {");
- out.println(" this.label = label;");
- out.println(" this.dataClass = dataClass;");
- out.println(" this.id = id;");
- out.println(" this.analogue = analogue;");
- out.println(" }");
- out.println();
-
- out.println(" public static " + className + " getType(int id) {");
- out.println(" return codeTypeMapping.get(id);");
- out.println(" }");
-
- out.println();
- out.println(" public String getLabel() {");
- out.println(" return label;");
- out.println(" }");
- out.println();
- out.println(" public Class> getDataClass() {");
- out.println(" return dataClass;");
- out.println(" }");
- out.println();
- out.println(" public int getId() {");
- out.println(" return id;");
- out.println(" }");
- out.println();
- out.println(" public boolean isAnalog() {");
- out.println(" return analogue;");
- out.println(" }");
- out.println("}");
-
- out.flush();
- out.close();
- }
-
- private static void outputClassGenerated(PrintWriter out) {
- out.println("@Generated(value = \"" + ZclProtocolCodeGenerator.class.getName() + "\", date = \"" + generatedDate
- + "\")");
- }
-
- private static void generateZclProfileTypeEnumeration(Context context, String packageRootPrefix,
- File sourceRootPath) throws IOException {
- final String className = "ZigBeeProfileType";
-
- final String packageRoot = packageRootPrefix;
- final String packagePath = getPackagePath(sourceRootPath, "");
- final File packageFile = getPackageFile(packagePath);
-
- final PrintWriter out = getClassOut(packageFile, className);
-
- CodeGeneratorUtil.outputLicense(out);
-
- out.println("package " + packageRoot + ";");
- out.println();
- out.println("import java.util.Map;");
- out.println("import java.util.HashMap;");
- out.println();
- out.println("import javax.annotation.Generated;");
-
- out.println();
- outputClassJavaDoc(out, "Enumeration of ZigBee profile types");
- outputClassGenerated(out);
- out.println("public enum " + className + " {");
-
- out.println(" UNKNOWN(-1, \"Unknown Profile\"),");
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- out.print(" " + profile.profileType + "(" + String.format("0x%04X", profile.profileId) + ", \""
- + profile.profileName + "\")");
- out.println(profiles.getLast().equals(profile) ? ';' : ',');
- }
-
- out.println();
- out.println(" /*");
- out.println(" * The ZigBee profile ID");
- out.println(" */");
- out.println(" private final int profileId;");
- out.println();
- out.println(" /*");
- out.println(" * The ZigBee profile label");
- out.println(" */");
- out.println(" private final String label;");
- out.println();
- out.println(" /**");
- out.println(" * Map containing the link of profile type value to the enum");
- out.println(" */");
- out.println(" private static Map map = null;");
- out.println();
-
- out.println(" static {");
- out.println(" map = new HashMap();");
- out.println(" for (" + className + " profileType : values()) {");
- out.println(" map.put(profileType.profileId, profileType);");
- out.println(" }");
- out.println(" }");
- out.println();
-
- out.println(" " + className + "(final int profileId, final String label) {");
- out.println(" this.profileId = profileId;");
- out.println(" this.label = label;");
- out.println(" }");
- out.println();
- out.println(" /*");
- out.println(" * Get the ZigBee profile ID");
- out.println(" *");
- out.println(" * @ return the profile ID");
- out.println(" */");
- out.println(" public int getId() {");
- out.println(" return profileId;");
- out.println(" }");
- out.println();
- out.println(" /*");
- out.println(" * Get the ZigBee profile label");
- out.println(" *");
- out.println(" * @ return the profile label");
- out.println(" */");
- out.println(" public String getLabel() {");
- out.println(" return label;");
- out.println(" }");
- out.println();
-
- out.println(" /**");
- out.println(" * Get a {@link " + className + "} from an integer");
- out.println(" *");
- out.println(" * @param profileTypeValue integer value defining the profile type");
- out.println(" * @return {@link " + className + "} or {@link #UNKNOWN} if the value could not be converted");
- out.println(" */");
- out.println(" public static " + className + " getProfileType(int profileTypeValue) {");
- out.println(" if (map.get(profileTypeValue) == null) {");
- out.println(" return UNKNOWN;");
- out.println(" }");
- out.println(" return map.get(profileTypeValue);");
- out.println(" }");
-
- out.println("}");
-
- out.flush();
- out.close();
- }
-
- private static void generateZclClusterTypeEnumeration(Context context, String packageRootPrefix,
- File sourceRootPath) throws IOException {
- final String className = "ZclClusterType";
-
- final String packageRoot = packageRootPrefix + packageZclProtocol;
- final String packagePath = getPackagePath(sourceRootPath, packageZclProtocol);
- final File packageFile = getPackageFile(packagePath);
-
- final PrintWriter out = getClassOut(packageFile, className);
-
- CodeGeneratorUtil.outputLicense(out);
-
- out.println("package " + packageRoot + ";");
- out.println();
- out.println("import " + packageRootPrefix + ".ZigBeeProfileType;");
- out.println("import " + packageRootPrefix + packageZcl + ".ZclCluster;");
- out.println("import " + packageRootPrefix + packageZclCluster + ".*;");
- out.println();
- out.println("import java.util.HashMap;");
- out.println("import java.util.Map;");
- out.println();
- out.println("import javax.annotation.Generated;");
-
- out.println();
- outputClassJavaDoc(out, "Enumeration of ZigBee Clusters");
- outputClassGenerated(out);
- out.println("public enum " + className + " {");
-
- boolean first = true;
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- final LinkedList clusters = new LinkedList(profile.clusters.values());
- for (final Cluster cluster : clusters) {
- if (first == false) {
- out.println(",");
- }
- first = false;
- out.print(" " + cluster.clusterType + "(" + String.format("0x%04X", cluster.clusterId)
- + ", ZigBeeProfileType." + profile.profileType + ", Zcl" + cluster.nameUpperCamelCase
- + "Cluster.class, \"" + cluster.clusterName + "\")");
- }
- }
- out.println(";");
-
- out.println();
- out.println(
- " private static final Map idValueMap = new HashMap();");
- out.println();
- out.println(" private final int clusterId;");
- out.println(" private final ZigBeeProfileType profileType;");
- out.println(" private final String label;");
- out.println(" private final Class extends ZclCluster> clusterClass;");
- out.println();
- out.println(" " + className
- + "(final int clusterId, final ZigBeeProfileType profileType, final Class extends ZclCluster>clusterClass, final String label) {");
- out.println(" this.clusterId = clusterId;");
- out.println(" this.profileType = profileType;");
- out.println(" this.clusterClass = clusterClass;");
- out.println(" this.label = label;");
- out.println(" }");
- out.println();
- out.println(" static {");
- out.println(" for (final ZclClusterType value : values()) {");
- out.println(" idValueMap.put(value.clusterId, value);");
- out.println(" }");
- out.println(" }");
- out.println();
- out.println(" public int getId() {");
- out.println(" return clusterId;");
- out.println(" }");
- out.println();
- out.println(" public ZigBeeProfileType getProfileType() {");
- out.println(" return profileType;");
- out.println(" }");
- out.println();
- out.println(" public String getLabel() {");
- out.println(" return label;");
- out.println(" }");
- out.println();
- // out.println(" public String toString() {");
- // out.println(" return label;");
- // out.println(" }");
- // out.println();
- out.println(" public Class extends ZclCluster> getClusterClass() {");
- out.println(" return clusterClass;");
- out.println(" }");
- out.println();
- out.println(" public static ZclClusterType getValueById(final int clusterId) {");
- out.println(" return idValueMap.get(clusterId);");
- out.println(" }");
- out.println();
- out.println("}");
-
- out.flush();
- out.close();
- }
-
- private static void generateZclCommandTypeEnumerationXXXXX(Context context, String packageRootPrefix,
- File sourceRootPath) throws IOException {
-
- final String className = "ZclCommandTypeXXX";
-
- final String packageRoot = packageRootPrefix + packageZclProtocol;
- final String packagePath = getPackagePath(sourceRootPath, packageZclProtocol);
- final File packageFile = getPackageFile(packagePath);
-
- final PrintWriter out = getClassOut(packageFile, className);
-
- out.println("package " + packageRoot + ";");
- out.println();
- outputClassJavaDoc(out, "Enumeration of ZCL commands");
- outputClassGenerated(out);
- out.println("public enum " + className + " {");
-
- final LinkedList valueRows = new LinkedList();
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- final LinkedList clusters = new LinkedList(profile.clusters.values());
- for (final Cluster cluster : clusters) {
- {
- final LinkedList commands = new LinkedList(cluster.received.values());
- for (final Command command : commands) {
- final boolean generic = cluster.clusterId == 65535;
- valueRows.add(" " + command.commandType + "(" + command.commandId + ", ZclClusterType."
- + cluster.clusterType + ", \"" + command.commandLabel + "\", true, " + generic + ")");
- }
- }
- {
- final LinkedList commands = new LinkedList(cluster.generated.values());
- for (final Command command : commands) {
- final boolean generic = cluster.clusterId == 65535;
- valueRows.add(" " + command.commandType + "(" + command.commandId + ", ZclClusterType."
- + cluster.clusterType + ", \"" + command.commandLabel + "\", false, " + generic + ")");
- }
- }
- }
- }
-
- for (final String valueRow : valueRows) {
- out.print(valueRow);
- out.println(valueRows.getLast().equals(valueRow) ? ';' : ',');
- }
-
- out.println();
- out.println(" private final int id;");
- out.println(" private final ZclClusterType clusterType;");
- out.println(" private final String label;");
- out.println(" private final boolean received;");
- out.println(" private final boolean generic;");
- out.println();
- out.println(" " + className
- + "(final int id, final ZclClusterType clusterType, final String label, final boolean received, final boolean generic) {");
- out.println(" this.id = id;");
- out.println(" this.clusterType = clusterType;");
- out.println(" this.label = label;");
- out.println(" this.received = received;");
- out.println(" this.generic = generic;");
- out.println(" }");
- out.println();
- out.println(" public int getId() { return id; }");
- out.println(" public ZclClusterType getClusterType() { return clusterType; }");
- out.println(" public String getLabel() { return label; }");
- out.println(" public boolean isReceived() { return received; }");
- out.println(" public boolean isGeneric() { return generic; }");
- out.println(" public String toString() { return label; }");
- out.println("}");
-
- out.flush();
- out.close();
- }
-
- private static void generateZclAttributeTypeEnumeration(Context context, String packageRootPrefix,
- File sourceRootPath) throws IOException {
-
- final String className = "ZclAttributeType";
-
- final String packageRoot = packageRootPrefix + packageZclProtocol;
- final String packagePath = getPackagePath(sourceRootPath, packageZclProtocol);
- final File packageFile = getPackageFile(packagePath);
-
- final PrintWriter out = getClassOut(packageFile, className);
-
- CodeGeneratorUtil.outputLicense(out);
-
- out.println("package " + packageRoot + ";");
- out.println();
- outputClassJavaDoc(out, "Enumeration of ZigBee attributes");
- outputClassGenerated(out);
- out.println("public enum " + className + " {");
-
- boolean first = true;
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- final LinkedList clusters = new LinkedList(profile.clusters.values());
-
- for (final Cluster cluster : clusters) {
- for (final Attribute attribute : cluster.attributes.values()) {
- if (first == false) {
- out.println(",");
- }
- first = false;
- out.print(" " + attribute.enumName + "(0x" + String.format("%04X", cluster.clusterId) + ", 0x"
- + String.format("%04X", attribute.attributeId) + ", ZclDataType." + attribute.dataType
- + ")");
- }
- }
- }
- out.println(";");
-
- out.println();
- out.println(" private final int clusterId;");
- out.println(" private final int attributeId;");
- out.println(" private final ZclAttributeType attributeType;");
- out.println(" private final String label;");
- out.println(" private final boolean received;");
- out.println(" private final boolean generic;");
- out.println();
- out.println(" " + className + "(final int clusterId, final int attributeId, final ZclDataType dataType) {");
- out.println(" this.id = id;");
- out.println(" this.attributeType = attributeType;");
- out.println(" this.label = label;");
- out.println(" this.received = received;");
- out.println(" this.generic = generic;");
- out.println(" }");
- out.println();
- out.println(" public int getId() { return id; }");
- out.println(" public ZclAttributeType getAttributeType() { return attributeType; }");
- out.println(" public String getLabel() { return label; }");
- out.println(" public boolean isReceived() { return received; }");
- out.println(" public boolean isGeneric() { return generic; }");
- out.println(" public String toString() { return label; }");
- out.println("}");
-
- out.flush();
- out.close();
- }
-
- private static void generateZclFieldTypeEnumeration(Context context, String packageRootPrefix, File sourceRootPath)
- throws IOException {
- final String className = "ZclFieldType";
-
- final String packageRoot = packageRootPrefix + packageZclProtocol;
- final String packagePath = getPackagePath(sourceRootPath, packageZclProtocol);
- final File packageFile = getPackageFile(packagePath);
-
- final PrintWriter out = getClassOut(packageFile, className);
-
- CodeGeneratorUtil.outputLicense(out);
-
- out.println("package " + packageRoot + ";");
- out.println();
- outputClassJavaDoc(out, "Enumeration of ZCL fields");
- outputClassGenerated(out);
- out.println("public enum " + className + " {");
-
- final LinkedList valueRows = new LinkedList();
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- final LinkedList clusters = new LinkedList(profile.clusters.values());
- for (final Cluster cluster : clusters) {
- final ArrayList commands = new ArrayList();
- commands.addAll(cluster.received.values());
- commands.addAll(cluster.generated.values());
- for (final Command command : commands) {
- final LinkedList fields = new LinkedList(command.fields.values());
- for (final Field field : fields) {
- valueRows.add(" " + field.fieldType + "(" + field.fieldId + ", ZclCommandType."
- + command.commandType + ", \"" + field.fieldLabel + "\", ZclDataType." + field.dataType
- + ")");
- }
- }
- }
- }
-
- for (final String valueRow : valueRows) {
- out.print(valueRow);
- out.println(valueRows.getLast().equals(valueRow) ? ';' : ',');
- }
-
- out.println();
- out.println(" private final int id;");
- out.println(" private final ZclCommandType commandType;");
- out.println(" private final String label;");
- out.println(" private final ZclDataType dataType;");
- out.println();
- out.println(" " + className
- + "(final int id, final ZclCommandType commandType, final String label, final ZclDataType dataType) {");
- out.println(" this.id = id;");
- out.println(" this.commandType = commandType;");
- out.println(" this.label = label;");
- out.println(" this.dataType = dataType;");
- out.println(" }");
- out.println();
- out.println(" public int getId() { return id; }");
- out.println(" public ZclCommandType getCommandType() { return commandType; }");
- out.println(" public String getLabel() { return label; }");
- out.println(" public ZclDataType getDataType() { return dataType; }");
- out.println();
- out.println("}");
-
- out.flush();
- out.close();
- }
-
- private static void generateZclCommandClasses(Context context, String packageRootPrefix, File sourceRootPath)
- throws IOException {
-
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- final LinkedList clusters = new LinkedList(profile.clusters.values());
- for (final Cluster cluster : clusters) {
- final ArrayList commands = new ArrayList();
- commands.addAll(cluster.received.values());
- commands.addAll(cluster.generated.values());
- for (final Command command : commands) {
- final String packageRoot = packageRootPrefix + packageZclProtocolCommand + "."
- + cluster.clusterType.replace("_", "").toLowerCase();
- final String packagePath = getPackagePath(sourceRootPath, packageRoot);
- final File packageFile = getPackageFile(packagePath);
-
- final String className = command.nameUpperCamelCase;
- final PrintWriter out = getClassOut(packageFile, className);
-
- final LinkedList fields = new LinkedList(command.fields.values());
- boolean fieldWithDataTypeList = false;
- for (final Field field : fields) {
- if (field.dataTypeClass.startsWith("List")) {
- fieldWithDataTypeList = true;
- break;
- }
- }
- CodeGeneratorUtil.outputLicense(out);
-
- out.println("package " + packageRoot + ";");
- out.println();
- out.println("import javax.annotation.Generated;");
- out.println();
-
- // out.println("import " + packageRootPrefix + packageZcl + ".ZclCommandMessage;");
- out.println("import " + packageRootPrefix + packageZcl + ".ZclCommand;");
- // out.println("import " + packageRootPrefix + packageZcl + ".ZclField;");
- if (fields.size() > 0) {
- out.println("import " + packageRootPrefix + packageZcl + ".ZclFieldSerializer;");
- out.println("import " + packageRootPrefix + packageZcl + ".ZclFieldDeserializer;");
- out.println("import " + packageRootPrefix + packageZclProtocol + ".ZclDataType;");
- }
- out.println("import " + packageRootPrefix + packageZclProtocol + ".ZclCommandDirection;");
- // out.println("import " + packageRootPrefix + packageZclProtocol + ".ZclClusterType;");
- // out.println("import " + packageRootPrefix + packageZclProtocol + ".ZclCommandType;");
- // if (!fields.isEmpty()) {
- // out.println("import " + packageRootPrefix + packageZclProtocol + ".ZclFieldType;");
- // if (fieldWithDataTypeList) {
- // out.println("import " + packageRootPrefix + packageZclField + ".*;");
- // }
- // }
-
- if (fieldWithDataTypeList) {
- out.println();
- out.println("import java.util.List;");
- }
-
- // out.println("import java.util.Map;");
- // out.println("import java.util.HashMap;");
-
- for (final Field field : fields) {
- String packageName;
- if (field.dataTypeClass.contains("Descriptor")) {
- packageName = packageZdpDescriptors;
- } else {
- packageName = packageZclField;
- }
-
- String typeName;
- if (field.dataTypeClass.startsWith("List")) {
- typeName = field.dataTypeClass;
- typeName = typeName.substring(typeName.indexOf("<") + 1);
- typeName = typeName.substring(0, typeName.indexOf(">"));
- } else {
- typeName = field.dataTypeClass;
- }
-
- switch (typeName) {
- case "Integer":
- case "Boolean":
- case "Object":
- case "Long":
- case "String":
- case "int[]":
- continue;
- case "IeeeAddress":
- out.println("import " + packageRootPrefix + "." + typeName + ";");
- continue;
- case "ZclStatus":
- out.println("import " + packageRootPrefix + packageZcl + ".ZclStatus;");
- continue;
- case "ImageUpgradeStatus":
- out.println("import " + packageRootPrefix + packageZclField + ".ImageUpgradeStatus;");
- continue;
- }
-
- out.println("import " + packageRootPrefix + packageName + "." + typeName + ";");
- }
-
- out.println();
- out.println("/**");
- out.println(" * " + command.commandLabel + " value object class.");
-
- out.println(" * ");
- out.println(" * Cluster: " + cluster.clusterName + ". Command is sent "
- + (cluster.received.containsValue(command) ? "TO" : "FROM") + " the server.");
- out.println(" * This command is " + ((cluster.clusterType.equals("GENERAL"))
- ? "a generic command used across the profile."
- : "a specific command used for the " + cluster.clusterName + " cluster."));
-
- if (command.commandDescription.size() > 0) {
- out.println(" *
");
- outputWithLinebreak(out, "", command.commandDescription);
- }
-
- out.println(" *
");
- out.println(" * Code is auto-generated. Modifications may be overwritten!");
-
- out.println(" */");
- outputClassGenerated(out);
- out.println("public class " + className + " extends ZclCommand {");
-
- for (final Field field : fields) {
- out.println(" /**");
- out.println(" * " + field.fieldLabel + " command message field.");
- if (field.description.size() != 0) {
- out.println(" *
");
- outputWithLinebreak(out, " ", field.description);
- }
- out.println(" */");
- out.println(" private " + field.dataTypeClass + " " + field.nameLowerCamelCase + ";");
- out.println();
- }
-
- // if (fields.size() > 0) {
- // out.println(" static {");
- // for (final Field field : fields) {
- // out.println(" fields.put(" + field.fieldId + ", new ZclField(" + field.fieldId
- // + ", \"" + field.fieldLabel + "\", ZclDataType." + field.dataType + "));");
- // }
- // out.println(" }");
- // out.println();
- // }
-
- out.println(" /**");
- out.println(" * Default constructor.");
- out.println(" */");
- out.println(" public " + className + "() {");
- // out.println(" setType(ZclCommandType." + command.commandType + ");");
- out.println(" genericCommand = "
- + ((cluster.clusterType.equals("GENERAL")) ? "true" : "false") + ";");
- if (!cluster.clusterType.equals("GENERAL")) {
- out.println(" clusterId = " + cluster.clusterId + ";");
- }
- out.println(" commandId = " + command.commandId + ";");
-
- out.println(" commandDirection = ZclCommandDirection."
- + (cluster.received.containsValue(command) ? "CLIENT_TO_SERVER" : "SERVER_TO_CLIENT")
- + ";");
-
- out.println(" }");
- // out.println();
- // out.println(" /**");
- // out.println(" * Constructor copying field values from command message.");
- // out.println(" *");
- // out.println(" * @param fields a {@link Map} containing the value {@link Object}s");
- // out.println(" */");
- // out.println(" public " + className + "(final Map fields) {");
- // out.println(" this();");
- // for (final Field field : fields) {
- // out.println(" " + field.nameLowerCamelCase + " = (" + field.dataTypeClass
- // + ") fields.get(" + field.fieldId + ");");
- // }
- // out.println(" }");
- // out.println();
- // out.println(" @Override");
- // out.println(" public ZclCommandMessage toCommandMessage() {");
- // out.println(" final ZclCommandMessage message = super.toCommandMessage();");
- // for (final Field field : fields) {
- // out.println(" message.getFields().put(ZclFieldType." + field.fieldType + ","
- // + field.nameLowerCamelCase + ");");
- // }
- // out.println(" return message;");
- // out.println(" }");
-
- if (cluster.clusterType.equals("GENERAL")) {
- out.println();
- out.println(" /**");
- out.println(" * Sets the cluster ID for generic commands. {@link " + className
- + "} is a generic command.");
- out.println(" * ");
- out.println(
- " * For commands that are not generic, this method will do nothing as the cluster ID is fixed.");
- out.println(
- " * To test if a command is generic, use the {@link #isGenericCommand} method.");
- out.println(" *");
- out.println(
- " * @param clusterId the cluster ID used for generic commands as an {@link Integer}");
-
- out.println(" */");
- out.println(" @Override");
- out.println(" public void setClusterId(Integer clusterId) {");
- out.println(" this.clusterId = clusterId;");
- out.println(" }");
- }
-
- for (final Field field : fields) {
- out.println();
- out.println(" /**");
- out.println(" * Gets " + field.fieldLabel + ".");
- if (field.description.size() != 0) {
- out.println(" *");
- for (String line : field.description) {
- out.println(" * " + line);
- }
- }
- out.println(" *");
- out.println(" * @return the " + field.fieldLabel);
- out.println(" */");
- out.println(" public " + field.dataTypeClass + " get" + field.nameUpperCamelCase + "() {");
- out.println(" return " + field.nameLowerCamelCase + ";");
- out.println(" }");
- out.println();
- out.println(" /**");
- out.println(" * Sets " + field.fieldLabel + ".");
- if (field.description.size() != 0) {
- out.println(" *");
- outputWithLinebreak(out, " ", field.description);
- }
- out.println(" *");
- out.println(" * @param " + field.nameLowerCamelCase + " the " + field.fieldLabel);
- out.println(" */");
- out.println(" public void set" + field.nameUpperCamelCase + "(final " + field.dataTypeClass
- + " " + field.nameLowerCamelCase + ") {");
- out.println(
- " this." + field.nameLowerCamelCase + " = " + field.nameLowerCamelCase + ";");
- out.println(" }");
-
- }
-
- if (fields.size() > 0) {
- // out.println();
- // out.println(" @Override");
- // out.println(" public void setFieldValues(final Map values) {");
- // for (final Field field : fields) {
- // out.println(" " + field.nameLowerCamelCase + " = (" + field.dataTypeClass
- // + ") values.get(" + field.fieldId + ");");
- // }
- // out.println(" }");
-
- out.println();
- out.println(" @Override");
- out.println(" public void serialize(final ZclFieldSerializer serializer) {");
- for (final Field field : fields) {
- // Rules...
- // if listSizer == null, then just output the field
- // if listSizer != null and contains && then check the param bit
-
- if (field.listSizer != null) {
- if (field.listSizer.equals("statusResponse")) {
- // Special case where a ZclStatus may be sent, or, a list of results.
- // This checks for a single response
- out.println(" if (status == ZclStatus.SUCCESS) {");
- out.println(" serializer.serialize(status, ZclDataType.ZCL_STATUS);");
- out.println(" return;");
- out.println(" }");
- } else if (field.conditionOperator != null) {
- if (field.conditionOperator == "&&") {
- out.println(" if ((" + field.listSizer + " & " + field.condition
- + ") != 0) {");
- } else {
- out.println(" if (" + field.listSizer + " " + field.conditionOperator
- + " " + field.condition + ") {");
- }
- out.println(" serializer.serialize(" + field.nameLowerCamelCase
- + ", ZclDataType." + field.dataType + ");");
- out.println(" }");
- } else {
- out.println(" for (int cnt = 0; cnt < " + field.nameLowerCamelCase
- + ".size(); cnt++) {");
- out.println(" serializer.serialize(" + field.nameLowerCamelCase
- + ".get(cnt), ZclDataType." + field.dataType + ");");
- out.println(" }");
- }
- } else {
- out.println(" serializer.serialize(" + field.nameLowerCamelCase
- + ", ZclDataType." + field.dataType + ");");
- }
- }
- out.println(" }");
-
- out.println();
- out.println(" @Override");
- out.println(" public void deserialize(final ZclFieldDeserializer deserializer) {");
- for (final Field field : fields) {
- if (field.listSizer != null) {
- if (field.listSizer.equals("statusResponse")) {
- // Special case where a ZclStatus may be sent, or, a list of results.
- // This checks for a single response
- out.println(" if (deserializer.getRemainingLength() == 1) {");
- out.println(
- " status = (ZclStatus) deserializer.deserialize(ZclDataType.ZCL_STATUS);");
- out.println(" return;");
- out.println(" }");
- } else if (field.conditionOperator != null) {
- if (field.conditionOperator == "&&") {
- out.println(" if ((" + field.listSizer + " & " + field.condition
- + ") != 0) {");
- } else {
- out.println(" if (" + field.listSizer + " " + field.conditionOperator
- + " " + field.condition + ") {");
- }
- out.println(" " + field.nameLowerCamelCase + " = (" + field.dataTypeClass
- + ") deserializer.deserialize(" + "ZclDataType." + field.dataType + ");");
- out.println(" }");
- } else {
- out.println(" for (int cnt = 0; cnt < " + field.nameLowerCamelCase
- + ".size(); cnt++) {");
- out.println(" " + field.nameLowerCamelCase + " = (" + field.dataTypeClass
- + ") deserializer.deserialize(" + "ZclDataType." + field.dataType + ");");
- out.println(" }");
- }
- } else {
- out.println(" " + field.nameLowerCamelCase + " = (" + field.dataTypeClass
- + ") deserializer.deserialize(" + "ZclDataType." + field.dataType + ");");
- }
- }
- out.println(" }");
- }
-
- int fieldLen = 0;
- for (final Field field : fields) {
- fieldLen += field.nameLowerCamelCase.length() + 20;
- }
-
- out.println();
- out.println(" @Override");
- out.println(" public String toString() {");
- out.println(" final StringBuilder builder = new StringBuilder("
- + (className.length() + 3 + fieldLen) + ");");
-
- out.println(" builder.append(\"" + className + " [\");");
- out.println(" builder.append(super.toString());");
- for (final Field field : fields) {
- out.println(" builder.append(\", " + field.nameLowerCamelCase + "=\");");
- out.println(" builder.append(" + field.nameLowerCamelCase + ");");
- }
- out.println(" builder.append(\']\');");
- out.println(" return builder.toString();");
- out.println(" }");
-
- out.println();
- out.println("}");
-
- out.flush();
- out.close();
- }
- }
- }
- }
-
- private static String getZclCommandTypeEnum(final Cluster cluster, final Command command, String string) {
- return command.commandType + "(" + String.format("0x%04X", cluster.clusterId) + ", " + command.commandId + ", "
- + command.nameUpperCamelCase + ".class" + ", " + string + ")";
- // return command.commandType + "(ZclClusterType." + cluster.clusterType + ", " + command.commandId + ", "
- // + command.nameUpperCamelCase + ".class" + ", " + received + ")";
- }
-
- private static void generateZclCommandTypeEnumeration(Context context, String packageRootPrefix,
- File sourceRootPath) throws IOException {
- final String className = "ZclCommandType";
-
- final String packageRoot = packageRootPrefix + packageZclProtocol;
- final String packagePath = getPackagePath(sourceRootPath, packageZclProtocol);
- final File packageFile = getPackageFile(packagePath);
-
- final PrintWriter out = getClassOut(packageFile, className);
-
- CodeGeneratorUtil.outputLicense(out);
-
- out.println("package " + packageRoot + ";");
- out.println();
-
- out.println("import java.lang.reflect.Constructor;");
- out.println();
- out.println("import javax.annotation.Generated;");
- out.println();
- out.println("import " + packageRootPrefix + packageZcl + ".ZclCommand;");
- out.println("import " + packageRootPrefix + packageZclProtocol + ".ZclCommandDirection;");
- out.println();
-
- Map commandEnum = new TreeMap();
-
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- final LinkedList clusters = new LinkedList(profile.clusters.values());
- for (final Cluster cluster : clusters) {
- // Brute force to get the commands in order!
- for (int c = 0; c < 65535; c++) {
- if (cluster.received.get(c) != null) {
- out.println("import " + getZclClusterCommandPackage(packageRootPrefix, cluster) + "."
- + cluster.received.get(c).nameUpperCamelCase + ";");
-
- commandEnum.put(getZclCommandTypeEnum(cluster, cluster.received.get(c),
- "ZclCommandDirection.CLIENT_TO_SERVER"), cluster.received.get(c));
- }
- if (cluster.generated.get(c) != null) {
- out.println("import " + getZclClusterCommandPackage(packageRootPrefix, cluster) + "."
- + cluster.generated.get(c).nameUpperCamelCase + ";");
-
- commandEnum.put(getZclCommandTypeEnum(cluster, cluster.generated.get(c),
- "ZclCommandDirection.SERVER_TO_CLIENT"), cluster.generated.get(c));
- }
- }
- }
- }
- out.println();
-
- out.println();
- outputClassJavaDoc(out, "Enumeration of ZigBee Cluster Library commands");
- outputClassGenerated(out);
- out.println("public enum " + className + " {");
- boolean first = true;
- for (String command : commandEnum.keySet()) {
- Command cmd = commandEnum.get(command);
- if (cmd == null) {
- System.out.println("Command without data: " + command);
- continue;
- }
-
- if (!first) {
- out.println(",");
- }
- first = false;
- out.println(" /**");
- out.println(" * " + cmd.commandType + ": " + cmd.commandLabel);
- out.println(" * ");
- out.println(" * See {@link " + cmd.nameUpperCamelCase + "}");
- out.println(" */");
- out.print(" " + command);
- }
- out.println(";");
- out.println();
-
- out.println(" private final int commandId;");
- out.println(" private final int clusterType;");
- out.println(" private final Class extends ZclCommand> commandClass;");
- // out.println(" private final String label;");
- out.println(" private final ZclCommandDirection direction;");
- out.println();
- out.println(" " + className
- + "(final int clusterType, final int commandId, final Class extends ZclCommand> commandClass, final ZclCommandDirection direction) {");
- out.println(" this.clusterType = clusterType;");
- out.println(" this.commandId = commandId;");
- out.println(" this.commandClass = commandClass;");
- // out.println(" this.label = label;");
- out.println(" this.direction = direction;");
- out.println(" }");
- out.println();
-
- out.println(" public int getClusterType() {");
- out.println(" return clusterType;");
- out.println(" }");
- out.println();
- out.println(" public int getId() {");
- out.println(" return commandId;");
- out.println(" }");
- out.println();
- // out.println(" public String getLabel() { return label; }");
- out.println(" public boolean isGeneric() {");
- out.println(" return clusterType==0xFFFF;");
- out.println(" }");
- out.println();
- out.println(" public ZclCommandDirection getDirection() {");
- out.println(" return direction;");
- out.println(" }");
- out.println();
- out.println(" public Class extends ZclCommand> getCommandClass() {");
- out.println(" return commandClass;");
- out.println(" }");
- out.println();
- out.println(
- " public static ZclCommandType getCommandType(final int clusterType, final int commandId,\n");
- out.println(" ZclCommandDirection direction) {\n");
- out.println(" for (final ZclCommandType value : values()) {\n");
- out.println(
- " if (value.direction == direction && value.clusterType == clusterType && value.commandId == commandId) {\n");
- out.println(" return value;\n");
- out.println(" }\n");
- out.println(" }\n");
- out.println(" return null;\n");
- out.println(" }");
-
- out.println();
- out.println(" public static ZclCommandType getGeneric(final int commandId) {");
- out.println(" for (final ZclCommandType value : values()) {");
- out.println(" if (value.clusterType == 0xFFFF && value.commandId == commandId) {");
- out.println(" return value;");
- out.println(" }");
- out.println(" }");
- out.println(" return null;");
- out.println(" }");
-
- out.println();
- out.println(" public ZclCommand instantiateCommand() {");
- out.println(" Constructor extends ZclCommand> cmdConstructor;");
- out.println(" try {");
- out.println(" cmdConstructor = commandClass.getConstructor();");
- out.println(" return cmdConstructor.newInstance();");
- out.println(" } catch (Exception e) {");
- out.println(" // logger.debug(\"Error instantiating cluster command {}\", this);");
- out.println(" }");
- out.println(" return null;");
- out.println(" }");
-
- out.println("}");
-
- out.flush();
- out.close();
- }
-
- protected static void outputWithLinebreak(PrintWriter out, String indent, List lines) {
- for (String line : lines) {
- String[] words = line.split(" ");
- if (words.length == 0) {
- return;
- }
-
- out.print(indent + " *");
-
- int len = 2;
- for (String word : words) {
- // if (word.toLowerCase().equals("note:")) {
- // if (len > 2) {
- // out.println();
- // }
- // out.println(indent + " * ");
- // out.print(indent + " * Note:");
- // continue;
- // }
- if (len + word.length() > lineLen) {
- out.println();
- out.print(indent + " *");
- len = 2;
- }
- out.print(" ");
- out.print(word);
- len += word.length();
- }
-
- if (len != 0) {
- out.println();
- }
- }
- }
-
- private static void generateZclClusterClasses(Context context, String packageRootPrefix, File sourceRootPath)
- throws IOException {
-
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- final LinkedList clusters = new LinkedList(profile.clusters.values());
- for (final Cluster cluster : clusters) {
- final String packageRoot = packageRootPrefix;
- final String packagePath = getPackagePath(sourceRootPath, packageRoot);
- final File packageFile = getPackageFile(packagePath + (packageZclCluster).replace('.', '/'));
-
- final String className = "Zcl" + cluster.nameUpperCamelCase + "Cluster";
- final PrintWriter out = getClassOut(packageFile, className);
-
- final ArrayList commands = new ArrayList();
- commands.addAll(cluster.received.values());
- commands.addAll(cluster.generated.values());
-
- CodeGeneratorUtil.outputLicense(out);
-
- out.println("package " + packageRoot + packageZclCluster + ";");
- out.println();
-
- Set imports = new HashSet();
-
- boolean useList = false;
- for (final Command command : commands) {
- final LinkedList fields = new LinkedList(command.fields.values());
- System.out.println("Checking command " + command.commandLabel);
-
- for (final Field field : fields) {
- System.out.println("Checking " + field.dataTypeClass);
- String packageName;
- if (field.dataTypeClass.contains("Descriptor")) {
- packageName = packageZdpDescriptors;
- } else {
- packageName = packageZclField;
- }
-
- String typeName;
- if (field.dataTypeClass.startsWith("List")) {
- useList = true;
- typeName = field.dataTypeClass;
- typeName = typeName.substring(typeName.indexOf("<") + 1);
- typeName = typeName.substring(0, typeName.indexOf(">"));
- } else {
- typeName = field.dataTypeClass;
- }
-
- switch (typeName) {
- case "Integer":
- case "Boolean":
- case "Object":
- case "Long":
- case "String":
- case "int[]":
- continue;
- case "IeeeAddress":
- imports.add(packageRootPrefix + "." + typeName);
- System.out.println("Adding " + typeName);
- continue;
- case "ZclStatus":
- imports.add(packageRootPrefix + packageZcl + ".ZclStatus");
- continue;
- case "ImageUpgradeStatus":
- imports.add(packageRootPrefix + packageZclField + ".ImageUpgradeStatus");
- continue;
- }
-
- imports.add(packageRootPrefix + packageName + "." + typeName);
- }
- }
-
- if (useList) {
- imports.add("java.util.List");
- // imports.add(packageRootPrefix + packageZclField + ".*");
- }
-
- boolean addAttributeTypes = false;
- boolean readAttributes = false;
- boolean writeAttributes = false;
- for (final Attribute attribute : cluster.attributes.values()) {
- if (attribute.attributeAccess.toLowerCase().contains("write")) {
- addAttributeTypes = true;
- writeAttributes = true;
- }
- if (attribute.attributeAccess.toLowerCase().contains("read")) {
- readAttributes = true;
- }
-
- if ("Calendar".equals(attribute.dataTypeClass)) {
- imports.add("java.util.Calendar");
- }
- if ("IeeeAddress".equals(attribute.dataTypeClass)) {
- imports.add("com.zsmartsystems.zigbee.IeeeAddress");
- }
- if ("ImageUpgradeStatus".equals(attribute.dataTypeClass)) {
- imports.add(packageRootPrefix + packageZclField + ".ImageUpgradeStatus");
- }
- }
-
- if (addAttributeTypes) {
- imports.add("com.zsmartsystems.zigbee.zcl.protocol.ZclDataType");
- }
-
- imports.add(packageRoot + packageZcl + ".ZclCluster");
- if (cluster.attributes.size() != 0) {
- imports.add(packageRoot + packageZclProtocol + ".ZclDataType");
- }
-
- if (!commands.isEmpty()) {
- imports.add(packageRoot + packageZcl + ".ZclCommand");
- }
- // imports.add(packageRoot + packageZcl + ".ZclCommandMessage");
- imports.add("javax.annotation.Generated");
-
- // imports.add(packageRoot + ".ZigBeeDestination");
- imports.add(packageRoot + ".ZigBeeEndpoint");
- if (!cluster.attributes.isEmpty() | !commands.isEmpty()) {
- imports.add(packageRoot + ".CommandResult");
- }
- // imports.add(packageRoot + ".ZigBeeEndpoint");
- imports.add(packageRoot + packageZcl + ".ZclAttribute");
- imports.add("java.util.Map");
- imports.add("java.util.concurrent.ConcurrentHashMap");
-
- if (!cluster.attributes.isEmpty() | !commands.isEmpty()) {
- imports.add("java.util.concurrent.Future");
- }
- // imports.add("com.zsmartsystems.zigbee.model.ZigBeeType");
-
- for (final Attribute attribute : cluster.attributes.values()) {
- if (attribute.attributeAccess.toLowerCase().contains("read")) {
- // imports.add("java.util.Calendar");
- }
- }
-
- for (final Command command : commands) {
- imports.add(getZclClusterCommandPackage(packageRoot, cluster) + "." + command.nameUpperCamelCase);
- }
-
- if (!cluster.attributes.isEmpty()) {
- imports.add(packageRoot + packageZclProtocol + ".ZclClusterType");
- }
-
- List importList = new ArrayList();
- importList.addAll(imports);
- Collections.sort(importList);
- for (final String importClass : importList) {
- out.println("import " + importClass + ";");
- }
-
- out.println();
- out.println("/**");
- out.println(" * " + cluster.clusterName + " cluster implementation (Cluster ID "
- + String.format("0x%04X", cluster.clusterId) + ").");
- if (cluster.clusterDescription.size() > 0) {
- out.println(" * ");
- }
- outputWithLinebreak(out, "", cluster.clusterDescription);
-
- out.println(" *
");
- out.println(" * Code is auto-generated. Modifications may be overwritten!");
-
- out.println(" */");
- // outputClassJavaDoc(out);
- outputClassGenerated(out);
- out.println("public class " + className + " extends ZclCluster {");
-
- out.println(" /**");
- out.println(" * The ZigBee Cluster Library Cluster ID");
- out.println(" */");
- out.println(" public static final int CLUSTER_ID = " + String.format("0x%04X;", cluster.clusterId));
- out.println();
- out.println(" /**");
- out.println(" * The ZigBee Cluster Library Cluster Name");
- out.println(" */");
- out.println(" public static final String CLUSTER_NAME = \"" + cluster.clusterName + "\";");
- out.println();
-
- if (cluster.attributes.size() != 0) {
- out.println(" // Attribute constants");
- for (final Attribute attribute : cluster.attributes.values()) {
- out.println(" /**");
- outputWithLinebreak(out, " ", attribute.attributeDescription);
-
- out.println(" */");
- out.println(" public static final int " + attribute.enumName + " = "
- + String.format("0x%04X", attribute.attributeId) + ";");
- }
- out.println();
- }
-
- out.println(" // Attribute initialisation");
- out.println(" protected Map initializeAttributes() {");
- out.println(
- " Map attributeMap = new ConcurrentHashMap("
- + cluster.attributes.size() + ");");
-
- if (cluster.attributes.size() != 0) {
- out.println();
- for (final Attribute attribute : cluster.attributes.values()) {
- out.println(" attributeMap.put(" + attribute.enumName
- + ", new ZclAttribute(ZclClusterType." + cluster.clusterType + ", " + attribute.enumName
- + ", \"" + attribute.attributeLabel + "\", " + "ZclDataType." + attribute.dataType
- + ", " + "mandatory".equals(attribute.attributeImplementation.toLowerCase()) + ", "
- + attribute.attributeAccess.toLowerCase().contains("read") + ", "
- + attribute.attributeAccess.toLowerCase().contains("write") + ", "
- + "mandatory".equals(attribute.attributeReporting.toLowerCase()) + "));");
- }
- }
- out.println();
- out.println(" return attributeMap;");
- out.println(" }");
- out.println();
-
- out.println(" /**");
- out.println(" * Default constructor to create a " + cluster.clusterName + " cluster.");
- out.println(" *");
- out.println(" * @param zigbeeEndpoint the {@link ZigBeeEndpoint}");
- out.println(" */");
- out.println(" public " + className + "(final ZigBeeEndpoint zigbeeEndpoint) {");
- out.println(" super(zigbeeEndpoint, CLUSTER_ID, CLUSTER_NAME);");
- out.println(" }");
-
- for (final Attribute attribute : cluster.attributes.values()) {
- DataTypeMap zclDataType = ZclDataType.getDataTypeMapping().get(attribute.dataType);
-
- if (attribute.attributeAccess.toLowerCase().contains("write")) {
- outputAttributeJavaDoc(out, "Set", attribute, zclDataType);
- out.println(" public Future set"
- + attribute.nameUpperCamelCase.replace("_", "") + "(final Object value) {");
- out.println(" return write(attributes.get(" + attribute.enumName + "), value);");
- out.println(" }");
- }
-
- if (attribute.attributeAccess.toLowerCase().contains("read")) {
- outputAttributeJavaDoc(out, "Get", attribute, zclDataType);
- out.println(" public Future get"
- + attribute.nameUpperCamelCase.replace("_", "") + "Async() {");
- out.println(" return read(attributes.get(" + attribute.enumName + "));");
- out.println(" }");
- outputAttributeJavaDoc(out, "Synchronously get", attribute, zclDataType);
- out.println(" public " + attribute.dataTypeClass + " get"
- + attribute.nameUpperCamelCase.replace("_", "") + "(final long refreshPeriod) {");
- out.println(" if (attributes.get(" + attribute.enumName
- + ").isLastValueCurrent(refreshPeriod)) {");
- out.println(" return (" + attribute.dataTypeClass + ") attributes.get("
- + attribute.enumName + ").getLastValue();");
- out.println(" }");
- out.println();
- out.println(" return (" + attribute.dataTypeClass + ") readSync(attributes.get("
- + attribute.enumName + "));");
- out.println(" }");
- }
-
- if (attribute.attributeAccess.toLowerCase().contains("read")
- && attribute.attributeReporting.toLowerCase().equals("mandatory")) {
- outputAttributeJavaDoc(out, "Set reporting for", attribute, zclDataType);
- if (zclDataType.analogue) {
- out.println(" public Future set" + attribute.nameUpperCamelCase
- + "Reporting(final int minInterval, final int maxInterval, final Object reportableChange) {");
- out.println(" return setReporting(attributes.get(" + attribute.enumName
- + "), minInterval, maxInterval, reportableChange);");
- } else {
- out.println(" public Future set" + attribute.nameUpperCamelCase
- + "Reporting(final int minInterval, final int maxInterval) {");
- out.println(" return setReporting(attributes.get(" + attribute.enumName
- + "), minInterval, maxInterval);");
- }
- out.println(" }");
- }
- }
-
- for (final Command command : commands) {
- out.println();
- out.println(" /**");
- out.println(" * The " + command.commandLabel);
- if (command.commandDescription.size() != 0) {
- out.println(" * ");
- outputWithLinebreak(out, " ", command.commandDescription);
- }
- out.println(" *");
-
- final LinkedList fields = new LinkedList(command.fields.values());
- for (final Field field : fields) {
- out.println(" * @param " + field.nameLowerCamelCase + " {@link " + field.dataTypeClass
- + "} " + field.fieldLabel);
- }
-
- out.println(" * @return the {@link Future} command result future");
- out.println(" */");
- out.print(" public Future " + command.nameLowerCamelCase + "(");
-
- boolean first = true;
- for (final Field field : fields) {
- if (first == false) {
- out.print(", ");
- }
- out.print(field.dataTypeClass + " " + field.nameLowerCamelCase);
- first = false;
- }
-
- out.println(") {");
- out.println(" " + command.nameUpperCamelCase + " command = new " + command.nameUpperCamelCase
- + "();");
- if (fields.size() != 0) {
- out.println();
- out.println(" // Set the fields");
- }
- for (final Field field : fields) {
- out.println(" command.set" + field.nameUpperCamelCase + "(" + field.nameLowerCamelCase
- + ");");
- }
- out.println();
- out.println(" return send(command);");
- out.println(" }");
- }
-
- // if (readAttributes) {
- // out.println();
- // out.println(" /**");
- // out.println(" * Add a binding for this cluster to the local node");
- // out.println(" *");
- // out.println(" * @return the {@link Future} command result future");
- // out.println(" */");
- // out.println(" public Future bind() {");
- // out.println(" return bind();");
- // out.println(" }");
- // }
-
- if (cluster.received.size() > 0) {
- out.println();
- out.println(" @Override");
- out.println(" public ZclCommand getCommandFromId(int commandId) {");
- out.println(" switch (commandId) {");
- for (final Command command : cluster.received.values()) {
- out.println(" case " + command.commandId + ": // " + command.commandType);
- out.println(" return new " + command.nameUpperCamelCase + "();");
- }
- out.println(" default:");
- out.println(" return null;");
- out.println(" }");
- out.println(" }");
- }
-
- if (cluster.generated.size() > 0) {
- out.println();
- out.println(" @Override");
- out.println(" public ZclCommand getResponseFromId(int commandId) {");
- out.println(" switch (commandId) {");
- for (final Command command : cluster.generated.values()) {
- out.println(" case " + command.commandId + ": // " + command.commandType);
- out.println(" return new " + command.nameUpperCamelCase + "();");
- }
- out.println(" default:");
- out.println(" return null;");
- out.println(" }");
- out.println(" }");
- }
-
- out.println("}");
-
- out.flush();
- out.close();
- }
- }
- }
-
- private static void generateAttributeEnumeration(Context context, String packageRootPrefix, File sourceRootPath)
- throws IOException {
-
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- final LinkedList clusters = new LinkedList(profile.clusters.values());
- for (final Cluster cluster : clusters) {
- if (cluster.attributes.size() != 0) {
- for (final Attribute attribute : cluster.attributes.values()) {
- if (attribute.valueMap.isEmpty()) {
- continue;
- }
-
- final String packageRoot = packageRootPrefix + packageZclProtocolCommand + "."
- + cluster.clusterType.replace("_", "").toLowerCase();
-
- final String className = attribute.nameUpperCamelCase + "Enum";
-
- outputEnum(packageRoot, sourceRootPath, className, attribute.valueMap, cluster.clusterName,
- attribute.attributeLabel);
- }
- }
- }
- }
- }
-
- private static void generateFieldEnumeration(Context context, String packageRootPrefix, File sourceRootPath)
- throws IOException {
-
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- final LinkedList clusters = new LinkedList(profile.clusters.values());
- for (final Cluster cluster : clusters) {
- final ArrayList commands = new ArrayList();
- commands.addAll(cluster.received.values());
- commands.addAll(cluster.generated.values());
-
- if (commands.size() != 0) {
- for (final Command command : commands) {
- for (final Field field : command.fields.values()) {
- if (field.valueMap.isEmpty()) {
- continue;
- }
-
- final String packageRoot = packageRootPrefix + packageZclProtocolCommand + "."
- + cluster.clusterType.replace("_", "").toLowerCase();
-
- final String className = field.nameUpperCamelCase + "Enum";
-
- outputEnum(packageRoot, sourceRootPath, className, field.valueMap, cluster.clusterName,
- field.fieldLabel);
- }
- }
- }
- }
- }
- }
-
- private static void outputEnum(String packageRoot, File sourceRootPath, String className,
- Map valueMap, String parentName, String label) throws IOException {
-
- final String packagePath = getPackagePath(sourceRootPath, packageRoot);
- final File packageFile = getPackageFile(packagePath);
-
- final PrintWriter out = getClassOut(packageFile, className);
-
- CodeGeneratorUtil.outputLicense(out);
-
- out.println("package " + packageRoot + ";");
-
- out.println();
- out.println("import java.util.HashMap;");
- out.println("import java.util.Map;");
- out.println();
- out.println("import javax.annotation.Generated;");
-
- out.println();
- outputClassJavaDoc(out, "Enumeration of " + parentName + " attribute " + label + " options.");
- outputClassGenerated(out);
- out.println("public enum " + className + " {");
- boolean first = true;
- for (final Integer key : valueMap.keySet()) {
- String value = valueMap.get(key);
-
- if (!first) {
- out.println(",");
- }
- first = false;
- // out.println(" /**");
- // out.println(" * " + cmd.commandLabel);
- // out.println(" * ");
- // out.println(" * See {@link " + cmd.nameUpperCamelCase + "}");
- // out.println(" */");
- out.print(" " + CodeGeneratorUtil.labelToEnumerationValue(value) + String.format("(0x%04X)", key));
- }
- out.println(";");
- out.println();
-
- out.println(" /**");
- out.println(" * A mapping between the integer code and its corresponding " + className
- + " type to facilitate lookup by value.");
- out.println(" */");
- out.println(" private static Map idMap;");
- out.println();
- out.println(" static {");
- out.println(" idMap = new HashMap();");
- out.println(" for (" + className + " enumValue : values()) {");
- out.println(" idMap.put(enumValue.key, enumValue);");
- out.println(" }");
- out.println(" }");
- out.println();
- out.println(" private final int key;");
- out.println();
- out.println(" " + className + "(final int key) {");
- out.println(" this.key = key;");
- out.println(" }");
- out.println();
-
- out.println(" public int getKey() {");
- out.println(" return key;");
- out.println(" }");
- out.println();
- out.println(" public static " + className + " getByValue(final int value) {");
- out.println(" return idMap.get(value);");
- out.println(" }");
- out.println("}");
-
- out.flush();
- out.close();
- }
-
- private static void outputAttributeJavaDoc(PrintWriter out, String type, Attribute attribute,
- DataTypeMap zclDataType) {
- out.println();
- out.println(" /**");
- out.println(" * " + type + " the " + attribute.attributeLabel + " attribute [attribute ID "
- + attribute.attributeId + "].");
- if (attribute.attributeDescription.size() != 0) {
- out.println(" * ");
- outputWithLinebreak(out, " ", attribute.attributeDescription);
- }
- if ("Synchronously get".equals(type)) {
- out.println(" *
");
- out.println(" * This method can return cached data if the attribute has already been received.");
- out.println(
- " * The parameter refreshPeriod is used to control this. If the attribute has been received");
- out.println(
- " * within refreshPeriod milliseconds, then the method will immediately return the last value");
- out.println(
- " * received. If refreshPeriod is set to 0, then the attribute will always be updated.");
- out.println(" *
");
- out.println(
- " * This method will block until the response is received or a timeout occurs unless the current value is returned.");
- }
- out.println(" *
");
- out.println(" * The attribute is of type {@link " + attribute.dataTypeClass + "}.");
- out.println(" *
");
- out.println(" * The implementation of this attribute by a device is "
- + attribute.attributeImplementation.toUpperCase());
- out.println(" *");
- if ("Set reporting for".equals(type)) {
- out.println(" * @param minInterval {@link int} minimum reporting period");
- out.println(" * @param maxInterval {@link int} maximum reporting period");
- if (zclDataType.analogue) {
- out.println(" * @param reportableChange {@link Object} delta required to trigger report");
- }
- } else if ("Set".equals(type)) {
- out.println(" * @param " + attribute.nameLowerCamelCase + " the {@link " + attribute.dataTypeClass
- + "} attribute value to be set");
- }
-
- if ("Synchronously get".equals(type)) {
- out.println(
- " * @param refreshPeriod the maximum age of the data (in milliseconds) before an update is needed");
- out.println(" * @return the {@link " + attribute.dataTypeClass + "} attribute value, or null on error");
- } else {
- out.println(" * @return the {@link Future} command result future");
- }
- out.println(" */");
- }
-
- private static PrintWriter getClassOut(File packageFile, String className) throws FileNotFoundException {
- final File classFile = new File(packageFile + File.separator + className + ".java");
- System.out.println("Generating: " + classFile.getAbsolutePath());
- final FileOutputStream fileOutputStream = new FileOutputStream(classFile, false);
- return new PrintWriter(fileOutputStream);
- }
-
- public static List splitString(String msg, int lineSize) {
- List res = new ArrayList();
-
- Pattern p = Pattern.compile("\\b.{1," + (lineSize - 1) + "}\\b\\W?");
- Matcher m = p.matcher(msg);
-
- while (m.find()) {
- System.out.println(m.group().trim()); // Debug
- res.add(m.group());
- }
- return res;
- }
-
- private static String getZclClusterCommandPackage(String packageRoot, Cluster cluster) {
- return packageRoot + packageZclProtocolCommand + "." + cluster.clusterType.replace("_", "").toLowerCase();
- }
-
- private static String getFieldType(Field field) {
- if (field.listSizer != null) {
- return "List<" + field.dataTypeClass + ">";
- } else {
- return field.dataTypeClass;
- }
- }
-
- private static void generateZdpCommandClasses(Context context, String packageRootPrefix, File sourceRootPath)
- throws IOException {
-
- // List of fields that are handled internally by super class
- List reservedFields = new ArrayList();
- reservedFields.add("status");
-
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- final LinkedList clusters = new LinkedList(profile.clusters.values());
- for (final Cluster cluster : clusters) {
- final ArrayList commands = new ArrayList();
- commands.addAll(cluster.received.values());
- commands.addAll(cluster.generated.values());
- for (final Command command : commands) {
- final String packageRoot = packageRootPrefix + packageZdpCommand;
- final String packagePath = getPackagePath(sourceRootPath, packageRoot);
- final File packageFile = getPackageFile(packagePath);
-
- final String className = command.nameUpperCamelCase;
- final PrintWriter out = getClassOut(packageFile, className);
-
- final LinkedList fields = new LinkedList(command.fields.values());
- boolean fieldWithDataTypeList = false;
- for (final Field field : fields) {
- if (field.listSizer != null) {
- fieldWithDataTypeList = true;
- break;
- }
-
- if (field.dataTypeClass.startsWith("List")) {
- fieldWithDataTypeList = true;
- break;
- }
- }
-
- CodeGeneratorUtil.outputLicense(out);
-
- out.println("package " + packageRoot + ";");
- out.println();
- // out.println("import " + packageRootPrefix + packageZcl + ".ZclCommandMessage;");
- // out.println("import " + packageRootPrefix + packageZdp + ".ZclCommand;");
- // out.println("import " + packageRootPrefix + packageZcl + ".ZclField;");
- if (fields.size() > 0) {
- out.println("import " + packageRootPrefix + packageZcl + ".ZclFieldSerializer;");
- out.println("import " + packageRootPrefix + packageZcl + ".ZclFieldDeserializer;");
- out.println("import " + packageRootPrefix + packageZclProtocol + ".ZclDataType;");
- }
-
- if (className.endsWith("Request")) {
- out.println("import " + packageRootPrefix + packageZdp + ".ZdoRequest;");
- } else {
- out.println("import " + packageRootPrefix + packageZdp + ".ZdoResponse;");
- }
-
- if (command.responseCommand != null && command.responseCommand.length() != 0) {
- out.println("import " + packageRootPrefix + ".ZigBeeCommand;");
- out.println("import " + packageRootPrefix + packageTransactionPrefix
- + ".ZigBeeTransactionMatcher;");
- out.println("import " + packageRootPrefix + packageZdpCommand + "." + command.responseCommand
- + ";");
- }
-
- if (fieldWithDataTypeList) {
- out.println();
- out.println("import java.util.List;");
- out.println("import java.util.ArrayList;");
- }
-
- out.println("import javax.annotation.Generated;");
-
- // out.println("import java.util.Map;");
- // out.println("import java.util.HashMap;");
-
- for (final Field field : fields) {
- String packageName;
- if (field.dataTypeClass.endsWith("Descriptor")) {
- packageName = packageZdpDescriptors;
- } else if (field.dataTypeClass.endsWith("Table")) {
- packageName = packageZdpDescriptors;
- } else {
- packageName = packageZclField;
- }
-
- String typeName;
- if (field.dataTypeClass.startsWith("List")) {
- typeName = field.dataTypeClass;
- typeName = typeName.substring(typeName.indexOf("<") + 1);
- typeName = typeName.substring(0, typeName.indexOf(">"));
- } else {
- typeName = field.dataTypeClass;
- }
-
- // if (reservedFields.contains(field.nameLowerCamelCase)) {
- // continue;
- // }
-
- switch (typeName) {
- case "Integer":
- case "Boolean":
- case "Object":
- case "Long":
- case "String":
- continue;
- case "IeeeAddress":
- out.println("import " + packageRootPrefix + "." + typeName + ";");
- continue;
- case "ZdoStatus":
- out.println("import " + packageRootPrefix + packageZdp + ".ZdoStatus;");
- continue;
- case "BindingTable":
- out.println("import " + packageRootPrefix + packageZdpField + ".BindingTable;");
- continue;
- case "NeighborTable":
- out.println("import " + packageRootPrefix + packageZdpField + ".NeighborTable;");
- continue;
- }
-
- out.println("import " + packageRootPrefix + packageName + "." + typeName + ";");
- }
-
- out.println();
- out.println("/**");
- out.println(" * " + command.commandLabel + " value object class.");
-
- if (command.commandDescription != null && command.commandDescription.size() != 0) {
- out.println(" * ");
- outputWithLinebreak(out, "", command.commandDescription);
- }
-
- if (cluster.clusterDescription.size() > 0) {
- out.println(" *
");
- outputWithLinebreak(out, "", cluster.clusterDescription);
- }
-
- out.println(" *
");
- out.println(" * Code is auto-generated. Modifications may be overwritten!");
-
- out.println(" */");
- out.println();
-
- outputClassGenerated(out);
-
- if (className.endsWith("Request")) {
- out.print("public class " + className + " extends ZdoRequest");
- } else {
- out.print("public class " + className + " extends ZdoResponse");
- }
-
- if (command.responseCommand != null && command.responseCommand.length() != 0) {
- out.print(" implements ZigBeeTransactionMatcher");
- }
- out.println(" {");
-
- for (final Field field : fields) {
- if (reservedFields.contains(field.nameLowerCamelCase)) {
- continue;
- }
-
- if (getAutoSized(fields, field.nameLowerCamelCase) != null) {
- continue;
- }
-
- out.println(" /**");
- out.println(" * " + field.fieldLabel + " command message field.");
- if (field.description.size() > 0) {
- out.println(" *
");
- outputWithLinebreak(out, " ", field.description);
- }
- out.println(" */");
- out.println(" private " + getFieldType(field) + " " + field.nameLowerCamelCase + ";");
- out.println();
- }
-
- // if (fields.size() > 0) {
- // out.println(" static {");
- // for (final Field field : fields) {
- // out.println(" fields.put(" + field.fieldId + ", new ZclField(" + field.fieldId
- // + ", \"" + field.fieldLabel + "\", ZclDataType." + field.dataType + "));");
- // }
- // out.println(" }");
- // out.println();
- // }
-
- out.println(" /**");
- out.println(" * Default constructor.");
- out.println(" */");
- out.println(" public " + className + "() {");
- // out.println(" setType(ZclCommandType." + command.commandType + ");");
- // out.println(" commandId = " + command.commandId + ";");
- out.println(" clusterId = " + String.format("0x%04X", command.commandId) + ";");
- // out.println(" commandDirection = "
- // + (cluster.received.containsValue(command) ? "true" : "false") + ";");
-
- out.println(" }");
-
- for (final Field field : fields) {
- if (reservedFields.contains(field.nameLowerCamelCase)) {
- continue;
- }
-
- if (getAutoSized(fields, field.nameLowerCamelCase) != null) {
- continue;
- }
-
- out.println();
- out.println(" /**");
- out.println(" * Gets " + field.fieldLabel + ".");
- if (field.description.size() != 0) {
- out.println(" *
");
- outputWithLinebreak(out, " ", field.description);
- }
- out.println(" *");
- out.println(" * @return the " + field.fieldLabel);
- out.println(" */");
- out.println(" public " + getFieldType(field) + " get" + field.nameUpperCamelCase + "() {");
- out.println(" return " + field.nameLowerCamelCase + ";");
- out.println(" }");
- out.println();
- out.println(" /**");
- out.println(" * Sets " + field.fieldLabel + ".");
- if (field.description.size() != 0) {
- out.println(" *
");
- outputWithLinebreak(out, " ", field.description);
- }
- out.println(" *");
- out.println(" * @param " + field.nameLowerCamelCase + " the " + field.fieldLabel);
- out.println(" */");
- out.println(" public void set" + field.nameUpperCamelCase + "(final " + getFieldType(field)
- + " " + field.nameLowerCamelCase + ") {");
- out.println(
- " this." + field.nameLowerCamelCase + " = " + field.nameLowerCamelCase + ";");
- out.println(" }");
-
- }
-
- if (fields.size() > 0) {
- // out.println();
- // out.println(" @Override");
- // out.println(" public void setFieldValues(final Map values) {");
- // for (final Field field : fields) {
- // out.println(" " + field.nameLowerCamelCase + " = (" + field.dataTypeClass
- // + ") values.get(" + field.fieldId + ");");
- // }
- // out.println(" }");
-
- out.println();
- out.println(" @Override");
- out.println(" public void serialize(final ZclFieldSerializer serializer) {");
- out.println(" super.serialize(serializer);");
- out.println();
- for (final Field field : fields) {
- if (getAutoSized(fields, field.nameLowerCamelCase) != null) {
- Field sizedField = getAutoSized(fields, field.nameLowerCamelCase);
- out.println(" serializer.serialize(" + sizedField.nameLowerCamelCase
- + ".size(), ZclDataType." + field.dataType + ");");
-
- continue;
- }
-
- if (field.listSizer != null) {
- out.println(" for (int cnt = 0; cnt < " + field.nameLowerCamelCase
- + ".size(); cnt++) {");
- out.println(" serializer.serialize(" + field.nameLowerCamelCase
- + ".get(cnt), ZclDataType." + field.dataType + ");");
- out.println(" }");
- } else {
- out.println(" serializer.serialize(" + field.nameLowerCamelCase
- + ", ZclDataType." + field.dataType + ");");
- }
- }
- out.println(" }");
-
- out.println();
- out.println(" @Override");
- out.println(" public void deserialize(final ZclFieldDeserializer deserializer) {");
- out.println(" super.deserialize(deserializer);");
- out.println();
- boolean first = true;
- for (final Field field : fields) {
- if (field.listSizer != null) {
- if (first) {
- out.println(" // Create lists");
- first = false;
- }
- out.println(" " + field.nameLowerCamelCase + " = new ArrayList<"
- + field.dataTypeClass + ">();");
- }
- }
- if (first == false) {
- out.println();
- }
- for (final Field field : fields) {
- if (field.completeOnZero) {
- out.println(" if (deserializer.isEndOfStream()) {");
- out.println(" return;");
- out.println(" }");
- }
- if (getAutoSized(fields, field.nameLowerCamelCase) != null) {
- out.println(" Integer " + field.nameLowerCamelCase + " = (" + field.dataTypeClass
- + ") deserializer.deserialize(" + "ZclDataType." + field.dataType + ");");
- continue;
- }
-
- if (field.listSizer != null) {
- out.println(" if (" + field.listSizer + " != null) {");
- out.println(" for (int cnt = 0; cnt < " + field.listSizer + "; cnt++) {");
- out.println(" " + field.nameLowerCamelCase + ".add(("
- + field.dataTypeClass + ") deserializer.deserialize(" + "ZclDataType."
- + field.dataType + "));");
- out.println(" }");
- out.println(" }");
- } else {
- out.println(" " + field.nameLowerCamelCase + " = (" + field.dataTypeClass
- + ") deserializer.deserialize(" + "ZclDataType." + field.dataType + ");");
- }
- if (field.completeOnZero) {
- out.println(" if (" + field.nameLowerCamelCase + " == 0) {");
- out.println(" return;");
- out.println(" }");
- }
-
- if (field.nameLowerCamelCase.equals("status")) {
- out.println(" if (status != ZdoStatus.SUCCESS) {");
- out.println(" // Don't read the full response if we have an error");
- out.println(" return;");
- out.println(" }");
- }
- }
- out.println(" }");
- }
-
- if (command.responseCommand != null && command.responseCommand.length() != 0) {
- out.println();
- out.println(" @Override");
- out.println(
- " public boolean isTransactionMatch(ZigBeeCommand request, ZigBeeCommand response) {");
- out.println(" if (!(response instanceof " + command.responseCommand + ")) {");
- out.println(" return false;");
- out.println(" }");
- out.println();
- out.print(" return ");
- // out.println("(((" + command.nameUpperCamelCase + ") request).getDestinationAddress()");
- // out.print(" .equals(((" + command.responseCommand
- // + ") response).getSourceAddress()))");
-
- boolean first = true;
- for (String matcher : command.responseMatchers.keySet()) {
- if (first == false) {
- out.println();
- out.print(" && ");
- }
- first = false;
- out.println("(((" + command.nameUpperCamelCase + ") request).get" + matcher + "()");
- out.print(" .equals(((" + command.responseCommand + ") response).get"
- + command.responseMatchers.get(matcher) + "()))");
- }
-
- // Default address checker
- if (first == true) {
- out.print("((ZdoRequest) request).getDestinationAddress().equals((("
- + command.responseCommand + ") response).getSourceAddress())");
- }
-
- out.print(";");
- out.println();
- out.println(" }");
- }
-
- int fieldLen = 0;
- for (final Field field : fields) {
- fieldLen += field.nameLowerCamelCase.length() + 20;
- }
-
- out.println();
- out.println(" @Override");
- out.println(" public String toString() {");
- out.println(" final StringBuilder builder = new StringBuilder("
- + (className.length() + 3 + fieldLen) + ");");
- out.println(" builder.append(\"" + className + " [\");");
- out.println(" builder.append(super.toString());");
- for (final Field field : fields) {
- if (getAutoSized(fields, field.nameLowerCamelCase) != null) {
- continue;
- }
-
- out.println(" builder.append(\", " + field.nameLowerCamelCase + "=\");");
- out.println(" builder.append(" + field.nameLowerCamelCase + ");");
- }
- out.println(" builder.append(\']\');");
- out.println(" return builder.toString();");
- out.println(" }");
-
- out.println();
- out.println("}");
-
- out.flush();
- out.close();
- }
- }
- }
- }
-
- private static Field getAutoSized(LinkedList fields, String name) {
- for (Field field : fields) {
- if (name.equals(field.listSizer)) {
- return field;
- }
- }
- return null;
- }
-
- private static String getZdoCommandTypeEnum(final Cluster cluster, final Command command, boolean received) {
- return command.commandType + "(" + String.format("0x%04X", command.commandId) + ", "
- + command.nameUpperCamelCase + ".class" + ")";
- }
-
- private static String getZdpClusterCommandPackage(String packageRoot, Cluster cluster) {
- return packageRoot + packageZdpCommand + "." + cluster.clusterType.replace("_", "").toLowerCase();
- }
-
- private static void generateZdoCommandTypeEnumeration(Context context, String packageRootPrefix,
- File sourceRootPath) throws IOException {
- final String className = "ZdoCommandType";
-
- final String packageRoot = packageRootPrefix + packageZdp;
- final String packagePath = getPackagePath(sourceRootPath, packageRoot);
- final File packageFile = getPackageFile(packagePath);
-
- final PrintWriter out = getClassOut(packageFile, className);
-
- CodeGeneratorUtil.outputLicense(out);
-
- out.println("package " + packageRoot + ";");
- out.println();
-
- Map commandEnum = new TreeMap();
-
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- final LinkedList clusters = new LinkedList(profile.clusters.values());
- for (final Cluster cluster : clusters) {
- // Brute force to get the commands in order!
- for (int c = 0; c < 65535; c++) {
- if (cluster.received.get(c) != null) {
- out.println("import " + packageRootPrefix + packageZdpCommand + "."
- + cluster.received.get(c).nameUpperCamelCase + ";");
-
- commandEnum.put(getZdoCommandTypeEnum(cluster, cluster.received.get(c), true),
- cluster.received.get(c));
- }
- }
- }
- }
- out.println();
-
- out.println();
- outputClassJavaDoc(out, "Enumeration of ZDP commands");
- out.println("public enum " + className + " {");
- boolean first = true;
- for (String command : commandEnum.keySet()) {
- Command cmd = commandEnum.get(command);
- if (cmd == null) {
- System.out.println("Command without data: " + command);
- continue;
- }
-
- if (!first) {
- out.println(",");
- }
- first = false;
- out.println(" /**");
- out.println(" * " + cmd.commandLabel);
- out.println(" * ");
- out.println(" * See {@link " + cmd.nameUpperCamelCase + "}");
- out.println(" */");
- out.print(" " + command);
- }
- out.println(";");
-
- out.println();
- out.println(" private final int clusterId;");
- out.println(" private final Class extends ZdoCommand> commandClass;");
- out.println();
- out.println(" " + className + "(final int clusterId, final Class extends ZdoCommand> commandClass) {");
- out.println(" this.clusterId = clusterId;");
- out.println(" this.commandClass = commandClass;");
- // out.println(" this.label = label;");
- out.println(" }");
- out.println();
-
- out.println(" public int getClusterId() {");
- out.println(" return clusterId;");
- out.println(" }");
- out.println();
- out.println(" public Class extends ZdoCommand> getCommandClass() {");
- out.println(" return commandClass;");
- out.println(" }");
- out.println();
- out.println(" public static ZdoCommandType getValueById(final int clusterId) {");
- out.println(" for (final ZdoCommandType value : values()) {");
- out.println(" if(value.clusterId == clusterId) {");
- out.println(" return value;");
- out.println(" }");
- out.println(" }");
- out.println(" return null;");
- out.println(" }");
- out.println("}");
-
- out.flush();
- out.close();
- }
-
- private static void generateZdpCommandTransactions(Context context, String packageRootPrefix, File sourceRootPath)
- throws IOException {
-
- final LinkedList profiles = new LinkedList(context.profiles.values());
- for (final Profile profile : profiles) {
- final LinkedList clusters = new LinkedList(profile.clusters.values());
- for (final Cluster cluster : clusters) {
- final ArrayList commands = new ArrayList();
- commands.addAll(cluster.received.values());
- commands.addAll(cluster.generated.values());
- for (final Command command : commands) {
- if (command.responseCommand == null || command.responseCommand.length() == 0) {
- continue;
- }
-
- final String packageRoot = packageRootPrefix + packageZdpTransaction;
- final String packagePath = getPackagePath(sourceRootPath, packageRoot);
- final File packageFile = getPackageFile(packagePath);
-
- final String className = command.nameUpperCamelCase + "Transaction";
- final PrintWriter out = getClassOut(packageFile, className);
-
- out.println("package " + packageRoot + ";");
- out.println();
-
- // out.println("import " + packageRootPrefix + packageZcl + ".ZclCommandMessage;");
- // out.println("import " + packageRootPrefix + packageZdp + ".ZclCommand;");
- // out.println("import " + packageRootPrefix + packageZcl + ".ZclField;");
-
- out.println(
- "import " + packageRootPrefix + packageZdpCommand + "." + command.nameUpperCamelCase + ";");
- out.println(
- "import " + packageRootPrefix + packageZdpCommand + "." + command.responseCommand + ";");
-
- out.println("import " + packageRootPrefix + ".Command;");
- out.println(
- "import " + packageRootPrefix + packageTransactionPrefix + ".ZigBeeTransactionMatcher;");
- // out.println("import " + packageRootPrefix + packageZdp + ".ZdoRequest;");
- // out.println("import " + packageRootPrefix + packageZdp + ".ZdoResponse;");
-
- // out.println("import java.util.Map;");
- // out.println("import java.util.HashMap;");
-
- out.println();
- out.println("/**");
- out.println(" * " + command.commandLabel + " transaction class.");
-
- if (command.commandDescription != null && command.commandDescription.size() != 0) {
- out.println(" * ");
- outputWithLinebreak(out, "", command.commandDescription);
- }
-
- if (cluster.clusterDescription.size() > 0) {
- out.println(" *
");
- outputWithLinebreak(out, "", cluster.clusterDescription);
- }
-
- out.println(" *
");
- out.println(" * Code is auto-generated. Modifications may be overwritten!");
-
- out.println(" */");
- out.println("public class " + className + " implements ZigBeeTransactionMatcher {");
-
- // out.println(" /**");
- // out.println(" * Default constructor.");
- // out.println(" */");
- // out.println(" public " + className + "() {");
- // out.println(" }");
- // out.println(" setType(ZclCommandType." + command.commandType + ");");
- // out.println(" commandId = " + command.commandId + ";");
- // out.println(" commandDirection = "
- // + (cluster.received.containsValue(command) ? "true" : "false") + ";");
-
- out.println();
- out.println(" @Override");
- out.println(" public boolean isTransactionMatch(Command request, Command response) {");
- out.println(" if (response instanceof " + command.responseCommand + ") {");
- // out.println(" return ((" + command.nameUpperCamelCase + ") request).get"
- // + command.responseRequest + "() == ((" + command.responseCommand + ") response).get"
- // + command.responseResponse + "();");
- out.println(" } else {");
- out.println(" return false;");
- out.println(" }");
- out.println(" }");
-
- out.println();
- out.println("}");
-
- out.flush();
- out.close();
- }
- }
- }
- }
-
-}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZclProtocolDefinitionParser.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZclProtocolDefinitionParser.java
deleted file mode 100644
index 8e2afb418..000000000
--- a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZclProtocolDefinitionParser.java
+++ /dev/null
@@ -1,530 +0,0 @@
-/**
- * Copyright (c) 2016-2019 by the respective copyright holders.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- */
-package com.zsmartsystems.zigbee.autocode;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.TreeMap;
-
-import org.apache.commons.lang.StringUtils;
-
-import com.zsmartsystems.zigbee.autocode.zcl.Attribute;
-import com.zsmartsystems.zigbee.autocode.zcl.Cluster;
-import com.zsmartsystems.zigbee.autocode.zcl.Command;
-import com.zsmartsystems.zigbee.autocode.zcl.Context;
-import com.zsmartsystems.zigbee.autocode.zcl.DataType;
-import com.zsmartsystems.zigbee.autocode.zcl.Field;
-import com.zsmartsystems.zigbee.autocode.zcl.Profile;
-import com.zsmartsystems.zigbee.autocode.zcl.ZclDataType;
-
-/**
- * @author tlaukkan - Created on 4/10/2016.
- * @author Chris Jackson
- */
-public class ZclProtocolDefinitionParser {
- public static void parseProfiles(Context context) {
- while (context.lines.size() > 0) {
- final String line = context.lines.remove(0);
-
- if (line.startsWith("# ") && line.contains("[")) {
- context.profile = new Profile();
- context.profile.profileName = getHeaderTitle(line);
- context.profile.profileAbbreviation = getHeaderAbbreviation(line);
- context.profile.profileType = CodeGeneratorUtil.labelToEnumerationValue(context.profile.profileName);
- context.profile.profileId = getHeaderId(line);
- context.profiles.put(context.profile.profileId, context.profile);
- System.out.println("Profile: " + context.profile.profileName + " "
- + CodeGeneratorUtil.toHex(context.profile.profileId));
- parseFunctionalDomains(context);
- }
- }
- }
-
- private static void parseFunctionalDomains(Context context) {
- while (context.lines.size() > 0) {
- final String line = context.lines.remove(0);
-
- // Returning to previous level.
- if (line.startsWith("# ") && line.contains("[")) {
- context.lines.add(0, line);
- return;
- }
-
- if (line.startsWith("# ")) {
- final String functionalDomainName = getHeaderTitle(line);
- System.out.println(" Functional domain: " + functionalDomainName);
-
- parseClusters(context);
- }
- }
- }
-
- private static void parseClusters(Context context) {
- while (context.lines.size() > 0) {
- final String line = context.lines.remove(0);
-
- // Returning to previous level.
- if (line.startsWith("# ")) {
- context.lines.add(0, line);
- return;
- }
-
- if (line.startsWith("## ")) {
- context.cluster = new Cluster();
- context.cluster.clusterName = getHeaderTitle(line);
- context.cluster.clusterDescription = new ArrayList();
- context.cluster.clusterType = CodeGeneratorUtil.labelToEnumerationValue(context.cluster.clusterName);
- context.cluster.clusterId = getHeaderId(line);
- context.cluster.nameUpperCamelCase = CodeGeneratorUtil
- .labelToUpperCamelCase(context.cluster.clusterName);
- context.cluster.nameLowerCamelCase = CodeGeneratorUtil
- .upperCamelCaseToLowerCamelCase(context.cluster.clusterName);
- context.profile.clusters.put(context.cluster.clusterId, context.cluster);
- System.out.println(
- " " + CodeGeneratorUtil.toHex(context.cluster.clusterId) + ") " + context.cluster.clusterName);
-
- parseDirections(context);
- }
- }
- }
-
- private static void parseDirections(Context context) {
- boolean addBreak = false;
- while (context.lines.size() > 0) {
- final String line = context.lines.remove(0);
-
- // Returning to previous level.
- if (line.startsWith("# ") || line.startsWith("## ")) {
- context.lines.add(0, line);
- return;
- }
-
- if (line.startsWith("### ")) {
- addBreak = false;
-
- context.received = line.toLowerCase().contains("received");
- context.generated = line.toLowerCase().contains("generated");
- context.attribute = line.toLowerCase().contains("attributes");
- if (context.received) {
- System.out.println(" Received:");
- } else if (context.generated) {
- System.out.println(" Generated:");
- } else if (context.attribute) {
- System.out.println(" Attributes:");
-
- parseAttributes(context);
- continue;
- } else {
- System.out.println(" Unknown:");
- }
-
- parseCommands(context);
-
- continue;
- }
-
- if (context.cluster.clusterDescription.size() == 0 && line.trim().length() == 0) {
- continue;
- }
- if (line.trim().length() == 0) {
- addBreak = true;
- continue;
- }
- if (addBreak && context.cluster.clusterDescription.size() > 0) {
- context.cluster.clusterDescription.add("");
- addBreak = false;
- }
- context.cluster.clusterDescription.add(line.trim());
- }
- }
-
- private static void parseCommands(Context context) {
- boolean addBreak = false;
- Field field = null;
- while (context.lines.size() > 0) {
- final String line = context.lines.remove(0);
-
- // Returning to previous level.
- if (line.startsWith("# ") || line.startsWith("## ") || line.startsWith("### ")) {
- context.lines.add(0, line);
- return;
- }
-
- if (line.startsWith("##### Expected Response")) {
- parseExpectedResponse(context);
- continue;
- }
-
- if (line.startsWith("##### ")) {
- addBreak = false;
-
- for (Field fieldLoop : context.command.fields.values()) {
- if (fieldLoop.fieldLabel.equals(line.trim().substring(6))) {
- field = fieldLoop;
- break;
- }
- }
- if (field == null) {
- System.out.println("Error finding field \"" + line.trim().substring(6) + "\"");
- }
- continue;
- }
-
- if (line.startsWith("#### ")) {
- context.command = new Command();
- context.command.commandLabel = getHeaderTitle(line).trim();
- String splits[] = context.command.commandLabel.split(" ");
-
- if ("RESPONSE".equals(splits[splits.length - 2].toUpperCase())
- && "COMMAND".equals(splits[splits.length - 1].toUpperCase())) {
- StringBuilder sb = new StringBuilder();
- for (int c = 0; c < splits.length - 1; c++) {
- if (c != 0) {
- sb.append(" ");
- }
- sb.append(splits[c]);
- }
-
- context.command.commandLabel = sb.toString();
- }
-
- context.command.commandDescription = new ArrayList();
- context.command.commandType = CodeGeneratorUtil.labelToEnumerationValue(context.command.commandLabel);
- context.command.commandId = getHeaderId(line);
- context.command.nameUpperCamelCase = CodeGeneratorUtil
- .labelToUpperCamelCase(context.command.commandLabel);
- context.command.nameLowerCamelCase = CodeGeneratorUtil
- .upperCamelCaseToLowerCamelCase(context.command.nameUpperCamelCase);
- if (context.received) {
- context.cluster.received.put(context.command.commandId, context.command);
- } else {
- context.cluster.generated.put(context.command.commandId, context.command);
- }
- System.out.println(" " + CodeGeneratorUtil.toHex(context.command.commandId) + ") "
- + context.command.commandLabel);
-
- parseField(context);
- continue;
- }
-
- if (field == null) {
- continue;
- }
-
- if (line.startsWith("|") && !line.startsWith("|Id") && !line.startsWith("|-")) {
- final String row = line.trim().substring(1, line.length() - 1);
- final String[] columns = row.split("\\|");
- int value = Integer.parseInt(columns[0].trim().substring(2), 16);
- String label = columns[1].trim();
-
- field.valueMap.put(value, label);
- continue;
- }
- if (line.startsWith("|") && (line.startsWith("|Id") || line.startsWith("|-"))) {
- continue;
- }
-
- if (field.description.size() == 0 && line.trim().length() == 0) {
- continue;
- }
- if (line.trim().length() == 0) {
- addBreak = true;
- continue;
- }
- if (addBreak && field.description.size() > 0) {
- field.description.add("");
- addBreak = false;
- }
- field.description.add(line.trim());
- }
-
- }
-
- private static void parseField(Context context) {
- int fieldIndex = 0;
- boolean addBreak = false;
- while (context.lines.size() > 0) {
- final String line = context.lines.remove(0);
-
- // Returning to previous level.
- if (line.startsWith("#")) {
- context.lines.add(0, line);
- return;
- }
-
- if (line.startsWith("|") && !line.startsWith("|Field Name") && !line.startsWith("|-")) {
- final String row = line.trim().substring(1, line.length() - 1);
- final String[] columns = row.split("\\|");
- final Field field = new Field();
- field.description = new ArrayList();
- field.fieldId = fieldIndex;
- field.valueMap = new TreeMap();
-
- field.fieldLabel = columns[0].trim();
- if (field.fieldLabel.contains("[")) {
- String option = field.fieldLabel.substring(field.fieldLabel.indexOf("[") + 1,
- field.fieldLabel.indexOf("]"));
- field.fieldLabel = field.fieldLabel.substring(0, field.fieldLabel.indexOf("["));
- field.completeOnZero = true;
- }
-
- field.fieldType = context.command.commandType + "_"
- + CodeGeneratorUtil.labelToEnumerationValue(field.fieldLabel);
- field.nameUpperCamelCase = CodeGeneratorUtil.labelToEnumerationValue(field.fieldLabel);
- field.nameUpperCamelCase = CodeGeneratorUtil.labelToUpperCamelCase(field.fieldLabel);
- field.nameLowerCamelCase = CodeGeneratorUtil.upperCamelCaseToLowerCamelCase(field.nameUpperCamelCase);
-
- String dataTypeName = columns[1].trim();
- if (dataTypeName.contains("[")) {
- String fieldString = dataTypeName.substring(dataTypeName.indexOf("[") + 1,
- dataTypeName.indexOf("]"));
- if (fieldString.length() != 0) {
- String conditionOperator = "";
- String condition = "";
- if (fieldString.contains("&&")) {
- conditionOperator = "&&";
- }
- if (fieldString.contains(">=")) {
- conditionOperator = ">=";
- }
- if (fieldString.contains("==")) {
- conditionOperator = "==";
- }
-
- if (conditionOperator.length() != 0) {
- field.listSizer = fieldString.substring(0, fieldString.indexOf(conditionOperator));
- condition = fieldString
- .substring(fieldString.indexOf(conditionOperator) + conditionOperator.length());
-
- field.condition = condition;
- field.conditionOperator = conditionOperator;
- } else {
- field.listSizer = fieldString;
- }
- field.listSizer = CodeGeneratorUtil.labelToUpperCamelCase(field.listSizer);
- field.listSizer = CodeGeneratorUtil.upperCamelCaseToLowerCamelCase(field.listSizer);
-
- dataTypeName = dataTypeName.substring(0, dataTypeName.indexOf("["));
- }
- }
- field.dataType = CodeGeneratorUtil.labelToEnumerationValue(dataTypeName);
-
- final DataType dataType = new DataType();
- dataType.dataTypeName = dataTypeName;
- dataType.dataTypeType = field.dataType;
-
- dataType.dataTypeClass = ZclDataType.getDataTypeMapping().get(field.dataType).dataClass;
- if (dataType.dataTypeClass == null) {
- throw new IllegalArgumentException("Type not mapped: " + field.dataType);
- }
-
- field.dataTypeClass = dataType.dataTypeClass;
-
- context.dataTypes.put(field.dataType, dataType);
- context.command.fields.put(field.fieldId, field);
- System.out.println(" " + CodeGeneratorUtil.toHex(fieldIndex) + ") " + field.fieldLabel + ": "
- + dataType.dataTypeName);
- fieldIndex++;
- }
-
- if (line.startsWith("|Id") || line.startsWith("|-")) {
- continue;
- }
-
- if (line.startsWith("|")) {
- addBreak = false;
- continue;
- }
-
- if (context.command.commandDescription.size() == 0 && line.trim().length() == 0) {
- continue;
- }
- if (line.trim().length() == 0) {
- addBreak = true;
- continue;
- }
- if (addBreak) {
- context.command.commandDescription.add("
");
- addBreak = false;
- }
- context.command.commandDescription.add(line.trim());
- }
- }
-
- private static void parseExpectedResponse(Context context) {
- context.command.responseMatchers = new HashMap();
- while (context.lines.size() > 0) {
- final String line = context.lines.remove(0);
-
- // Returning to previous level.
- if (line.startsWith("#")) {
- context.lines.add(0, line);
- return;
- }
-
- if (line.startsWith("Packet: ")) {
- String cmd = line.substring(7);
- String splits[] = cmd.split(" ");
- StringBuilder sb = new StringBuilder();
- for (int c = 0; c < splits.length - 1; c++) {
- if (c != 0) {
- sb.append(" ");
- }
- sb.append(splits[c]);
- }
- context.command.responseCommand = CodeGeneratorUtil.labelToUpperCamelCase(line.substring(7));
- }
-
- if (line.startsWith("Match: ")) {
- String response = line.substring(7).trim();
- String[] matcher = response.split("==");
-
- String responseRequest = getMatcherResponse(matcher[0].trim());
- String responseResponse = getMatcherResponse(matcher[1].trim());
- context.command.responseMatchers.put(responseRequest, responseResponse);
- }
- }
- }
-
- private static String getMatcherResponse(String definition) {
- if (!definition.contains(".")) {
- return CodeGeneratorUtil.labelToUpperCamelCase(definition.trim());
- }
-
- String[] parts = definition.split("\\.");
- parts[0] = CodeGeneratorUtil.labelToUpperCamelCase(parts[0].trim());
- parts[1] = CodeGeneratorUtil.labelToUpperCamelCase(parts[1].trim());
- return parts[0] + "().get" + parts[1];
- }
-
- private static String getHeaderTitle(String line) {
- line = line.substring(line.lastIndexOf("#") + 1);
- if (line.contains("[")) {
- return StringUtils.substringBefore(line, "[").trim();
- } else {
- return line.trim();
- }
- }
-
- private static int getHeaderId(String line) {
- final String headerIdString = StringUtils.substringBetween(line, "[", "]").trim();
- return CodeGeneratorUtil.fromHex(headerIdString);
- }
-
- private static String getHeaderAbbreviation(String line) {
- return StringUtils.substringAfter(line, "]").trim().toLowerCase();
- }
-
- private static void parseAttributes(Context context) {
- Attribute attribute = null;
- while (context.lines.size() > 0) {
- final String line = context.lines.remove(0);
-
- // Returning to previous level.
- if (line.startsWith("# ") || line.startsWith("## ") || line.startsWith("### ")) {
- context.lines.add(0, line);
- return;
- }
-
- if (line.startsWith("|") && !line.startsWith("|Id") && !line.startsWith("|-")) {
- parseAttributeTable(context, line);
- }
-
- if (line.startsWith("#### ")) {
- attribute = null;
- for (Attribute attr : context.cluster.attributes.values()) {
- if (attr.attributeLabel
- .equals(getHeaderTitle(line).substring(0, getHeaderTitle(line).indexOf(" ")))) {
- attribute = attr;
- break;
- }
- }
-
- if (attribute == null) {
- System.out.println("***** Attribute not found: " + line);
- continue;
- }
- parseAttribute(context, attribute);
- continue;
- }
-
- }
- }
-
- private static void parseAttributeTable(Context context, String line) {
- final String row = line.trim().substring(1, line.length() - 1);
- final String[] columns = row.split("\\|");
- final Attribute attribute = new Attribute();
- attribute.valueMap = new TreeMap();
- attribute.attributeId = Integer.parseInt(columns[0].trim().substring(2), 16);
- attribute.attributeLabel = columns[1].trim();
- attribute.attributeDescription = new ArrayList();
- attribute.attributeAccess = columns[3].trim();
- attribute.attributeImplementation = columns[4].trim();
- attribute.attributeReporting = columns[5].trim();
- attribute.nameUpperCamelCase = CodeGeneratorUtil.labelToEnumerationValue(attribute.attributeLabel);
- attribute.nameUpperCamelCase = CodeGeneratorUtil.labelToUpperCamelCase(attribute.attributeLabel);
- attribute.nameLowerCamelCase = CodeGeneratorUtil.upperCamelCaseToLowerCamelCase(attribute.nameUpperCamelCase);
- attribute.dataType = CodeGeneratorUtil.labelToEnumerationValue(columns[2].trim());
- attribute.enumName = "ATTR_" + attribute.attributeLabel.toUpperCase();
- final DataType dataType = new DataType();
- dataType.dataTypeName = columns[2].trim();
- dataType.dataTypeType = attribute.dataType;
- System.out.println(" Type:::" + attribute.attributeLabel + ":: " + dataType.dataTypeType);
- dataType.dataTypeClass = ZclDataType.getDataTypeMapping().get(attribute.dataType).dataClass;
- if (dataType.dataTypeClass == null) {
- throw new IllegalArgumentException("Type not mapped: " + attribute.dataType);
- }
- attribute.dataTypeClass = dataType.dataTypeClass;
-
- context.dataTypes.put(attribute.dataType, dataType);
- context.cluster.attributes.put(attribute.attributeId, attribute);
- }
-
- private static void parseAttribute(Context context, Attribute attribute) {
- boolean addBreak = false;
- while (context.lines.size() > 0) {
- final String line = context.lines.remove(0);
-
- // Returning to previous level.
- if (line.startsWith("# ") || line.startsWith("## ") || line.startsWith("### ")
- || line.startsWith("#### ")) {
- context.lines.add(0, line);
- return;
- }
-
- if (line.startsWith("|") && !line.startsWith("|Id") && !line.startsWith("|-")) {
- final String row = line.trim().substring(1, line.length() - 1);
- final String[] columns = row.split("\\|");
- int value = Integer.parseInt(columns[0].trim().substring(2), 16);
- String label = columns[1].trim();
-
- attribute.valueMap.put(value, label);
- continue;
- }
-
- if (line.startsWith("|Id") || line.startsWith("|-")) {
- continue;
- }
-
- if ((attribute.attributeDescription.size() == 0 && line.trim().length() == 0)) {
- continue;
- }
- if (line.trim().length() == 0 && attribute.attributeDescription.size() > 0) {
- addBreak = true;
- continue;
- }
- if (addBreak && attribute.attributeDescription.size() > 0) {
- attribute.attributeDescription.add("");
- addBreak = false;
- }
- attribute.attributeDescription.add(line.trim());
- }
- }
-
-}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeBaseClassGenerator.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeBaseClassGenerator.java
new file mode 100644
index 000000000..ea3f62580
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeBaseClassGenerator.java
@@ -0,0 +1,468 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.zsmartsystems.zigbee.autocode.ZclDataType.DataTypeMap;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlAttribute;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlCluster;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlDescription;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlField;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+
+public abstract class ZigBeeBaseClassGenerator {
+ private final Logger log = LoggerFactory.getLogger(ZigBeeBaseClassGenerator.class);
+
+ String generatedDate;
+
+ Map dependencies;
+
+ int lineLen = 80;
+ String sourceRootPath;
+ private final String licenseText;
+ List importList = new ArrayList();
+
+ static String packageRoot = "com.zsmartsystems.zigbee";
+ static String packageZcl = ".zcl";
+ static String packageZclField = packageZcl + ".field";
+ String packageZclCluster = packageZcl + ".clusters";
+ String packageZclProtocol = packageZcl + ".protocol";
+ String packageZclProtocolCommand = packageZclCluster;
+
+ static String packageZdp = ".zdo";
+ static String packageZdpField = packageZdp + ".field";
+ String packageZdpCommand = packageZdp + ".command";
+ String packageZdpTransaction = packageZdp + ".transaction";
+ String packageZdpDescriptors = packageZdpField;
+
+ private static List standardTypes = new ArrayList<>();
+ private static Map customTypes = new HashMap<>();
+ private static List fixedCaseAcronyms = new ArrayList<>();
+ static {
+ fixedCaseAcronyms.add("AA");
+ fixedCaseAcronyms.add("AC");
+ fixedCaseAcronyms.add("AAA");
+ fixedCaseAcronyms.add("ACE");
+ fixedCaseAcronyms.add("APS");
+ fixedCaseAcronyms.add("CIE");
+ fixedCaseAcronyms.add("CR");
+ fixedCaseAcronyms.add("CO");
+ fixedCaseAcronyms.add("CO2");
+ fixedCaseAcronyms.add("DC");
+ fixedCaseAcronyms.add("DRLC");
+ fixedCaseAcronyms.add("DST");
+ fixedCaseAcronyms.add("ECC");
+ fixedCaseAcronyms.add("ECDSA");
+ fixedCaseAcronyms.add("EUI");
+ fixedCaseAcronyms.add("FC");
+ fixedCaseAcronyms.add("HAN");
+ fixedCaseAcronyms.add("HW");
+ fixedCaseAcronyms.add("ID");
+ fixedCaseAcronyms.add("IAS");
+ fixedCaseAcronyms.add("IEEE");
+ fixedCaseAcronyms.add("LQI");
+ fixedCaseAcronyms.add("MAC");
+ fixedCaseAcronyms.add("MMO");
+ fixedCaseAcronyms.add("NWK");
+ fixedCaseAcronyms.add("PIN");
+ fixedCaseAcronyms.add("PIR");
+ fixedCaseAcronyms.add("RMS");
+ fixedCaseAcronyms.add("RSSI");
+ fixedCaseAcronyms.add("SMAC");
+ fixedCaseAcronyms.add("SW");
+ fixedCaseAcronyms.add("UTC");
+ fixedCaseAcronyms.add("WAN");
+ fixedCaseAcronyms.add("WD");
+ fixedCaseAcronyms.add("XY");
+ fixedCaseAcronyms.add("ZCL");
+
+ fixedCaseAcronyms.add("may");
+ fixedCaseAcronyms.add("shall");
+ fixedCaseAcronyms.add("should");
+
+ fixedCaseAcronyms.add("ZigBee");
+
+ standardTypes.add("Integer");
+ standardTypes.add("Boolean");
+ standardTypes.add("Object");
+ standardTypes.add("Long");
+ standardTypes.add("String");
+ standardTypes.add("int[]");
+
+ customTypes.put("IeeeAddress", packageRoot + ".IeeeAddress");
+ customTypes.put("ByteArray", packageRoot + packageZclField + ".ByteArray");
+ customTypes.put("ZclStatus", packageRoot + packageZcl + ".ZclStatus");
+ customTypes.put("ZdoStatus", packageRoot + packageZdp + ".ZdoStatus");
+ customTypes.put("BindingTable", packageRoot + packageZdpField + ".BindingTable");
+ customTypes.put("NeighborTable", packageRoot + packageZdpField + ".NeighborTable");
+ customTypes.put("RoutingTable", packageRoot + packageZdpField + ".RoutingTable");
+ customTypes.put("Calendar", "java.util.Calendar");
+ customTypes.put("ImageUpgradeStatus", packageRoot + packageZclField + ".ImageUpgradeStatus");
+ }
+
+ ZigBeeBaseClassGenerator(String sourceRootPath, String licenseText) {
+ this.sourceRootPath = sourceRootPath;
+ this.licenseText = licenseText;
+ }
+
+ protected String stringToConstantEnum(String value) {
+ return stringToConstant(value).replaceAll("_", "");
+ }
+
+ protected String stringToConstant(String value) {
+ // value = value.replaceAll("\\(.*?\\) ?", "");
+ value = value.trim();
+ value = value.replace("+", "_Plus");
+ value = value.replace("(", "_");
+ value = value.replace(")", "_");
+ value = value.replace(" ", "_");
+ value = value.replace("-", "_");
+ value = value.replace(".", "_");
+ value = value.replace("/", "_");
+ value = value.replace("#", "_");
+ value = value.replaceAll("_+", "_");
+ if (value.endsWith("_")) {
+ value = value.substring(0, value.length() - 1);
+ }
+ return value.toUpperCase();
+ }
+
+ private String toProperCase(String s) {
+ return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
+ }
+
+ private String toCamelCase(String value) {
+ // value = value.replaceAll("\\(.*?\\) ?", "");
+ value = value.replace("(", "_");
+ value = value.replace(")", "_");
+ value = value.replace("+", "_Plus");
+ value = value.replace(" ", "_");
+ value = value.replace("-", "_");
+ value = value.replace(".", "_");
+ value = value.replace("/", "_");
+ value = value.replace("#", "_");
+ value = value.replaceAll("_+", "_");
+ String[] parts = value.split("_");
+ String camelCaseString = "";
+ for (String part : parts) {
+ camelCaseString = camelCaseString + toProperCase(part);
+ }
+ return camelCaseString;
+ }
+
+ protected String stringToUpperCamelCase(String value) {
+ return toCamelCase(value);
+ }
+
+ protected String stringToLowerCamelCase(String value) {
+ String cc = toCamelCase(value);
+
+ return cc.substring(0, 1).toLowerCase() + cc.substring(1);
+ }
+
+ protected String upperCaseFirstCharacter(String val) {
+ return val.substring(0, 1).toUpperCase() + val.substring(1);
+ }
+
+ protected String lowerCaseFirstCharacter(String val) {
+ return val.substring(0, 1).toLowerCase() + val.substring(1);
+ }
+
+ protected PrintWriter getClassOut(File packageFile, String className) throws FileNotFoundException {
+ packageFile.mkdirs();
+ final File classFile = new File(packageFile + File.separator + className + ".java");
+ log.debug("Generating: {}", classFile.getAbsolutePath());
+ final FileOutputStream fileOutputStream = new FileOutputStream(classFile, false);
+ return new PrintWriter(fileOutputStream);
+ }
+
+ protected void importsClear() {
+ importList.clear();
+ }
+
+ protected void importsAdd(String importClass) {
+ if (importList.contains(importClass)) {
+ return;
+ }
+ importList.add(importClass);
+ }
+
+ protected void outputImports(final PrintWriter out) {
+ Collections.sort(importList);
+ boolean found = false;
+ for (final String importClass : importList) {
+ if (!importClass.startsWith("java.")) {
+ continue;
+ }
+ found = true;
+ out.println("import " + importClass + ";");
+ }
+ if (found) {
+ out.println();
+ found = false;
+ }
+ for (final String importClass : importList) {
+ if (!importClass.startsWith("javax.")) {
+ continue;
+ }
+ found = true;
+ out.println("import " + importClass + ";");
+ }
+ if (found) {
+ out.println();
+ found = false;
+ }
+ for (final String importClass : importList) {
+ if (importClass.startsWith("java.") || importClass.startsWith("javax.")) {
+ continue;
+ }
+ out.println("import " + importClass + ";");
+ }
+ }
+
+ protected void outputWithLinebreak(PrintWriter out, String indent, List descriptions) {
+ boolean firstDescription = true;
+ for (ZigBeeXmlDescription description : descriptions) {
+ if (description.description == null) {
+ continue;
+ }
+ String[] words = description.description.split("\\s+");
+ if (words.length == 0) {
+ continue;
+ }
+
+ if (!firstDescription) {
+ out.println(indent + " * ");
+ }
+ firstDescription = false;
+
+ out.print(indent + " *");
+ int len = 2 + indent.length();
+
+ for (String word : words) {
+ if (word.equalsIgnoreCase("note:")) {
+ if (len > 2) {
+ out.println();
+ }
+ out.println(indent + " *
");
+ out.print(indent + " * Note:");
+ continue;
+ }
+ if (len + word.length() > lineLen) {
+ out.println();
+ out.print(indent + " *");
+ len = 2 + indent.length();
+ }
+ out.print(" ");
+
+ for (String acronym : fixedCaseAcronyms) {
+ if (acronym.equalsIgnoreCase(word)) {
+ word = acronym;
+ }
+ }
+
+ out.print(word);
+ len += word.length();
+ }
+
+ if (len != 0) {
+ out.println();
+ }
+ }
+ }
+
+ protected void outputLicense(PrintWriter out) {
+ out.println("/**");
+ for (String line: licenseText.split("\n")) {
+ out.println(" * " + line);
+
+ }
+ out.println(" */");
+ }
+
+ protected File getPackageFile(String packagePath) {
+ final File packageFile = new File(packagePath);
+ if (!packageFile.exists()) {
+ packageFile.mkdirs();
+ }
+ return packageFile;
+ }
+
+ protected String getPackagePath(File sourceRootPath, String packageRoot) {
+ return sourceRootPath.getAbsolutePath() + File.separator + packageRoot.replace(".", File.separator);
+ }
+
+ protected void outputClassGenerated(PrintWriter out) {
+ out.println("@Generated(value = \"" + getClass().getName() + "\", date = \"" + generatedDate
+ + "\")");
+ }
+
+ protected void outputAttributeJavaDoc(PrintWriter out, String type, ZigBeeXmlAttribute attribute,
+ DataTypeMap zclDataType) {
+ out.println();
+ out.println(" /**");
+ out.println(" * " + type + " the " + attribute.name + " attribute [attribute ID 0x"
+ + String.format("%04X", attribute.code) + "].");
+ if (attribute.description.size() != 0) {
+ out.println(" *
");
+ outputWithLinebreak(out, " ", attribute.description);
+ }
+ if ("Synchronously get".equals(type)) {
+ out.println(" *
");
+ out.println(" * This method can return cached data if the attribute has already been received.");
+ out.println(
+ " * The parameter refreshPeriod is used to control this. If the attribute has been received");
+ out.println(
+ " * within refreshPeriod milliseconds, then the method will immediately return the last value");
+ out.println(
+ " * received. If refreshPeriod is set to 0, then the attribute will always be updated.");
+ out.println(" *
");
+ out.println(
+ " * This method will block until the response is received or a timeout occurs unless the current value is returned.");
+ }
+ out.println(" *
");
+ out.println(" * The attribute is of type {@link " + getDataTypeClass(attribute) + "}.");
+ out.println(" *
");
+ out.println(" * The implementation of this attribute by a device is "
+ + (attribute.optional ? "OPTIONAL" : "MANDATORY"));
+ out.println(" *");
+ if (attribute.arrayCount != null && attribute.arrayStart != null) {
+ out.println(" * @param arrayOffset attribute array offset (" + attribute.arrayStart
+ + " < arrayOffset < " + (attribute.arrayStart + attribute.arrayCount - 1) + ")");
+ }
+ if ("Set reporting for".equals(type)) {
+ out.println(" * @param minInterval minimum reporting period");
+ out.println(" * @param maxInterval maximum reporting period");
+ if (zclDataType.analogue) {
+ out.println(" * @param reportableChange {@link Object} delta required to trigger report");
+ }
+ } else if ("Set".equals(type)) {
+ out.println(" * @param " + stringToLowerCamelCase(attribute.name) + " the {@link "
+ + getDataTypeClass(attribute) + "} attribute value to be set");
+ }
+
+ if ("Synchronously get".equals(type)) {
+ out.println(
+ " * @param refreshPeriod the maximum age of the data (in milliseconds) before an update is needed");
+ out.println(
+ " * @return the {@link " + getDataTypeClass(attribute) + "} attribute value, or null on error");
+ } else {
+ out.println(" * @return the {@link Future} command result future");
+ }
+ out.println(" */");
+ }
+
+ protected String getDataTypeClass(ZigBeeXmlAttribute attribute) {
+ // if (attribute.implementationClass.isEmpty()) {
+ if (ZclDataType.getDataTypeMapping().get(attribute.type) != null) {
+ return ZclDataType.getDataTypeMapping().get(attribute.type).dataClass;
+ }
+
+ if (dependencies.containsKey(attribute.implementationClass)) {
+ // importsAdd(dependencies.get(type));
+ return attribute.implementationClass;
+ }
+
+ log.warn("Unknown data type {}", attribute.type);
+ return "(UNKNOWN::" + attribute.type + ")";
+ // }
+ // return attribute.implementationClass;
+ }
+
+ protected String getDataTypeClass(ZigBeeXmlField field) {
+ String dataType = "";
+
+ // if (field.implementationClass.isEmpty()) {
+ if (ZclDataType.getDataTypeMapping().get(field.type) != null) {
+ dataType = ZclDataType.getDataTypeMapping().get(field.type).dataClass;
+ } else if (dependencies.containsKey(field.implementationClass)) {
+ // importsAdd(dependencies.get(type));
+ dataType = field.implementationClass;
+ }
+
+ if (dataType.isEmpty()) {
+ log.warn("Unknown data type {}", field.type);
+ return "(UNKNOWN::" + field.type + ")";
+ }
+
+ if (field.sizer == null) {
+ return dataType;
+ } else {
+ return "List<" + dataType + ">";
+ }
+
+ // }
+ // return field.implementationClass;
+ }
+
+ protected void importsAddClass(ZigBeeXmlField field) {
+ importsAddClassInternal(getDataTypeClass(field));
+ }
+
+ protected void importsAddClass(ZigBeeXmlAttribute attribute) {
+ importsAddClassInternal(getDataTypeClass(attribute));
+ }
+
+ protected void importsAddClassInternal(String type) {
+ String typeName = type;
+ if (type.startsWith("List")) {
+ importsAdd("java.util.List");
+ typeName = typeName.substring(typeName.indexOf("<") + 1, typeName.indexOf(">"));
+ }
+
+ if (standardTypes.contains(typeName)) {
+ return;
+ }
+
+ if (customTypes.containsKey(typeName)) {
+ importsAdd(customTypes.get(typeName));
+ return;
+ }
+
+ if (dependencies.containsKey(type)) {
+ importsAdd(dependencies.get(type));
+ return;
+ }
+
+ String packageName;
+ if (type.contains("Descriptor")) {
+ packageName = packageZdpDescriptors;
+ } else {
+ packageName = packageZclField;
+ }
+ importsAdd(packageRoot + packageName + "." + typeName);
+ }
+
+ protected String getZclClusterCommandPackage(ZigBeeXmlCluster cluster) {
+ if (cluster.name.startsWith("ZDO")) {
+ return packageRoot + packageZdpCommand;
+ } else {
+ return packageRoot + packageZclProtocolCommand + "."
+ + stringToLowerCamelCase(cluster.name).replace("_", "").toLowerCase();
+ }
+ }
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeBaseFieldGenerator.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeBaseFieldGenerator.java
new file mode 100644
index 000000000..52a1b25ae
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeBaseFieldGenerator.java
@@ -0,0 +1,284 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlField;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeBaseFieldGenerator extends ZigBeeBaseClassGenerator {
+ private final String OPERATOR_LOGIC_AND = "LOGIC_AND";
+ private final String OPERATOR_EQUAL = "EQUAL";
+ private final String OPERATOR_NOT_EQUAL = "NOT_EQUAL";
+ private final String OPERATOR_GREATER_THAN = "GREATER_THAN";
+ private final String OPERATOR_GREATER_THAN_OR_EQUAL = "GREATER_THAN_OR_EQUAL";
+ private final String OPERATOR_LESS_THAN = "LESS_THAN";
+ private final String OPERATOR_LESS_THAN_OR_EQUAL = "LESS_THAN_OR_EQUAL";
+
+ ZigBeeBaseFieldGenerator(String sourceRootPath, String licenseText) {
+ super(sourceRootPath, licenseText);
+ }
+
+ protected void generateFields(PrintWriter out, String parentClass, String className, List fields,
+ List reservedFields) {
+ for (final ZigBeeXmlField field : fields) {
+ if (reservedFields.contains(stringToLowerCamelCase(field.name))) {
+ continue;
+ }
+ if (getAutoSized(fields, stringToLowerCamelCase(field.name)) != null) {
+ continue;
+ }
+
+ out.println();
+ out.println(" /**");
+ out.println(" * Gets " + field.name + ".");
+ if (field.description.size() != 0) {
+ out.println(" * ");
+ outputWithLinebreak(out, " ", field.description);
+ }
+ out.println(" *");
+ out.println(" * @return the " + field.name);
+ out.println(" */");
+ out.println(" public " + getDataTypeClass(field) + " get" + stringToUpperCamelCase(field.name) + "() {");
+ out.println(" return " + stringToLowerCamelCase(field.name) + ";");
+ out.println(" }");
+ out.println();
+ out.println(" /**");
+ out.println(" * Sets " + field.name + ".");
+ if (field.description.size() != 0) {
+ out.println(" *
");
+ outputWithLinebreak(out, " ", field.description);
+ }
+ out.println(" *");
+ out.println(" * @param " + stringToLowerCamelCase(field.name) + " the " + field.name);
+ out.println(" */");
+ out.println(" public void set" + stringToUpperCamelCase(field.name) + "(final " + getDataTypeClass(field)
+ + " " + stringToLowerCamelCase(field.name) + ") {");
+ out.println(" this." + stringToLowerCamelCase(field.name) + " = "
+ + stringToLowerCamelCase(field.name) + ";");
+ out.println(" }");
+
+ }
+
+ if (fields.size() > 0) {
+ out.println();
+ out.println(" @Override");
+ out.println(" public void serialize(final ZclFieldSerializer serializer) {");
+ if (parentClass.startsWith("Zdo")) {
+ out.println(" super.serialize(serializer);");
+ out.println();
+ }
+
+ for (final ZigBeeXmlField field : fields) {
+ // if (reservedFields.contains(stringToLowerCamelCase(field.name))) {
+ // continue;
+ // }
+
+ // Rules...
+ // if listSizer == null, then just output the field
+ // if listSizer != null and contains && then check the param bit
+ if (getAutoSized(fields, stringToLowerCamelCase(field.name)) != null) {
+ ZigBeeXmlField sizedField = getAutoSized(fields, stringToLowerCamelCase(field.name));
+ out.println(" serializer.serialize(" + stringToLowerCamelCase(sizedField.name)
+ + ".size(), ZclDataType." + field.type + ");");
+
+ continue;
+ }
+
+ if (field.sizer != null) {
+ out.println(" for (int cnt = 0; cnt < " + stringToLowerCamelCase(field.name)
+ + ".size(); cnt++) {");
+ out.println(" serializer.serialize(" + stringToLowerCamelCase(field.name)
+ + ".get(cnt), ZclDataType." + field.type + ");");
+ out.println(" }");
+ } else if (field.condition != null) {
+ if (field.condition.value.equals("statusResponse")) {
+ // Special case where a ZclStatus may be sent, or, a list of results.
+ // This checks for a single response
+ out.println(" if (status == ZclStatus.SUCCESS) {");
+ out.println(" serializer.serialize(status, ZclDataType.ZCL_STATUS);");
+ out.println(" return;");
+ out.println(" }");
+ continue;
+ } else if (field.condition.operator.equals(OPERATOR_LOGIC_AND)) {
+ out.println(
+ " if ((" + field.condition.field + " & " + field.condition.value + ") != 0) {");
+ } else {
+ out.println(" if (" + field.condition.field + " " + getOperator(field.condition.operator)
+ + " " + field.condition.value + ") {");
+ }
+ out.println(" serializer.serialize(" + stringToLowerCamelCase(field.name)
+ + ", ZclDataType." + field.type + ");");
+ out.println(" }");
+ } else {
+ if (field.type != null && !field.type.isEmpty()) {
+ out.println(" serializer.serialize(" + stringToLowerCamelCase(field.name)
+ + ", ZclDataType." + field.type + ");");
+ } else {
+ out.println(" " + stringToLowerCamelCase(field.name) + ".serialize(serializer);");
+ }
+ }
+ }
+ out.println(" }");
+
+ out.println();
+ out.println(" @Override");
+ out.println(" public void deserialize(final ZclFieldDeserializer deserializer) {");
+ if (parentClass.startsWith("Zdo")) {
+ out.println(" super.deserialize(deserializer);");
+ out.println();
+ }
+ boolean first = true;
+ for (final ZigBeeXmlField field : fields) {
+ if (field.sizer != null) {
+ if (first) {
+ out.println(" // Create lists");
+ first = false;
+ }
+ out.println(" " + stringToLowerCamelCase(field.name) + " = new Array"
+ + getDataTypeClass(field) + "();");
+ }
+ }
+ if (first == false) {
+ out.println();
+ }
+ for (final ZigBeeXmlField field : fields) {
+ // if (reservedFields.contains(stringToLowerCamelCase(field.name))) {
+ // continue;
+ // }
+
+ if (field.completeOnZero) {
+ out.println(" if (deserializer.isEndOfStream()) {");
+ out.println(" return;");
+ out.println(" }");
+ }
+ if (getAutoSized(fields, stringToLowerCamelCase(field.name)) != null) {
+ out.println(
+ " Integer " + stringToLowerCamelCase(field.name) + " = (" + getDataTypeClass(field)
+ + ") deserializer.deserialize(" + "ZclDataType." + field.type + ");");
+ continue;
+ }
+
+ if (field.sizer != null) {
+ String dataType = getDataTypeClass(field).substring(getDataTypeClass(field).indexOf('<') + 1,
+ getDataTypeClass(field).indexOf('>'));
+
+ out.println(" if (" + field.sizer + " != null) {");
+ out.println(" for (int cnt = 0; cnt < " + field.sizer + "; cnt++) {");
+ out.println(" " + stringToLowerCamelCase(field.name) + ".add((" + dataType
+ + ") deserializer.deserialize(" + "ZclDataType." + field.type + "));");
+ out.println(" }");
+ out.println(" }");
+ } else if (field.condition != null) {
+ if (field.condition.value.equals("statusResponse")) {
+ // Special case where a ZclStatus may be sent, or, a list of results.
+ // This checks for a single response
+ out.println(" if (deserializer.getRemainingLength() == 1) {");
+ out.println(
+ " status = (ZclStatus) deserializer.deserialize(ZclDataType.ZCL_STATUS);");
+ out.println(" return;");
+ out.println(" }");
+ continue;
+ } else if (field.condition.operator.equals(OPERATOR_LOGIC_AND)) {
+ out.println(
+ " if ((" + field.condition.field + " & " + field.condition.value + ") != 0) {");
+ } else {
+ out.println(" if (" + field.condition.field + " " + getOperator(field.condition.operator)
+ + " " + field.condition.value + ") {");
+ }
+ out.println(" " + stringToLowerCamelCase(field.name) + " = (" + getDataTypeClass(field)
+ + ") deserializer.deserialize(" + "ZclDataType." + field.type + ");");
+ out.println(" }");
+ } else {
+ if (field.type != null && !field.type.isEmpty()) {
+ out.println(" " + stringToLowerCamelCase(field.name) + " = (" + getDataTypeClass(field)
+ + ") deserializer.deserialize(" + "ZclDataType." + field.type + ");");
+ } else {
+ out.println(" " + stringToLowerCamelCase(field.name) + " = new "
+ + getDataTypeClass(field) + "();");
+ out.println(" " + stringToLowerCamelCase(field.name) + ".deserialize(deserializer);");
+ }
+ }
+
+ if (field.name.toLowerCase().equals("status") && field.type.equals("ZDO_STATUS")) {
+ out.println(" if (status != ZdoStatus.SUCCESS) {");
+ out.println(" // Don't read the full response if we have an error");
+ out.println(" return;");
+ out.println(" }");
+ }
+ }
+ out.println(" }");
+ }
+ }
+
+ protected void generateToString(PrintWriter out, String className, List fields,
+ List reservedFields) {
+ int fieldLen = 0;
+ for (final ZigBeeXmlField field : fields) {
+ fieldLen += stringToLowerCamelCase(field.name).length() + 20;
+ }
+
+ out.println();
+ out.println(" @Override");
+ out.println(" public String toString() {");
+ out.println(" final StringBuilder builder = new StringBuilder(" + (className.length() + 3 + fieldLen)
+ + ");");
+
+ out.println(" builder.append(\"" + className + " [\");");
+ out.println(" builder.append(super.toString());");
+ for (final ZigBeeXmlField field : fields) {
+ // if (reservedFields.contains(stringToLowerCamelCase(field.name))) {
+ // continue;
+ // }
+ if (getAutoSized(fields, stringToLowerCamelCase(field.name)) != null) {
+ continue;
+ }
+ out.println(" builder.append(\", " + stringToLowerCamelCase(field.name) + "=\");");
+ out.println(" builder.append(" + stringToLowerCamelCase(field.name) + ");");
+ }
+ out.println(" builder.append(\']\');");
+ out.println(" return builder.toString();");
+ out.println(" }");
+ }
+
+ private String getOperator(String operator) {
+ switch (operator) {
+ case OPERATOR_LOGIC_AND:
+ return "&&";
+ case OPERATOR_EQUAL:
+ return "==";
+ case OPERATOR_NOT_EQUAL:
+ return "!=";
+ case OPERATOR_GREATER_THAN:
+ return ">";
+ case OPERATOR_GREATER_THAN_OR_EQUAL:
+ return ">=";
+ case OPERATOR_LESS_THAN:
+ return "<";
+ case OPERATOR_LESS_THAN_OR_EQUAL:
+ return "<";
+ default:
+ return "<>";
+ }
+ }
+
+ protected ZigBeeXmlField getAutoSized(List fields, String name) {
+ for (ZigBeeXmlField field : fields) {
+ if (name.equals(field.sizer)) {
+ return field;
+ }
+ }
+ return null;
+ }
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclClusterGenerator.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclClusterGenerator.java
new file mode 100644
index 000000000..b280008ea
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclClusterGenerator.java
@@ -0,0 +1,452 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import com.zsmartsystems.zigbee.autocode.ZclDataType.DataTypeMap;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlAttribute;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlCluster;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlCommand;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlField;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeZclClusterGenerator extends ZigBeeBaseClassGenerator {
+
+ ZigBeeZclClusterGenerator(String sourceRootPath, String licenseText, List clusters, String generatedDate, Map dependencies) {
+ super(sourceRootPath, licenseText);
+ this.generatedDate = generatedDate;
+ this.dependencies = dependencies;
+
+ for (ZigBeeXmlCluster cluster : clusters) {
+ // Suppress GENERAL cluster as it's not really a cluster!
+ if (cluster.name.equalsIgnoreCase("GENERAL")) {
+ continue;
+ }
+
+ try {
+ generateZclClusterClasses(cluster, packageRoot, new File(sourceRootPath));
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void generateZclClusterClasses(ZigBeeXmlCluster cluster, String packageRootPrefix, File sourceRootPath)
+ throws IOException {
+
+ final String packageRoot = packageRootPrefix;
+ final String packagePath = getPackagePath(sourceRootPath, packageRoot);
+ final File packageFile = getPackageFile(packagePath + (packageZclCluster).replace('.', '/'));
+
+ final String className = "Zcl" + stringToUpperCamelCase(cluster.name) + "Cluster";
+ final PrintWriter out = getClassOut(packageFile, className);
+
+ outputLicense(out);
+
+ out.println("package " + packageRoot + packageZclCluster + ";");
+ out.println();
+
+ importsClear();
+
+ int commandsServer = 0;
+ int commandsClient = 0;
+ for (final ZigBeeXmlCommand command : cluster.commands) {
+ importsAdd(packageRoot + packageZclCluster + "." + stringToLowerCamelCase(cluster.name).toLowerCase() + "."
+ + stringToUpperCamelCase(command.name));
+
+ if (command.source.equals("server")) {
+ commandsServer++;
+ }
+ if (command.source.equals("client")) {
+ commandsClient++;
+ }
+
+ for (final ZigBeeXmlField field : command.fields) {
+ importsAddClass(field);
+ }
+ }
+
+ boolean addAttributeTypes = false;
+ boolean readAttributes = false;
+ boolean writeAttributes = false;
+ int attributesServer = 0;
+ int attributesClient = 0;
+ for (final ZigBeeXmlAttribute attribute : cluster.attributes) {
+ if (attribute.writable) {
+ addAttributeTypes = true;
+ writeAttributes = true;
+ }
+ readAttributes = true;
+ if (attribute.side.equals("server")) {
+ attributesServer++;
+ }
+ if (attribute.side.equals("client")) {
+ attributesClient++;
+ }
+
+ importsAddClass(attribute);
+ }
+
+ if (addAttributeTypes) {
+ importsAdd("com.zsmartsystems.zigbee.zcl.protocol.ZclDataType");
+ }
+
+ importsAdd(packageRoot + packageZcl + ".ZclCluster");
+ if (attributesServer > 0) {
+ importsAdd(packageRoot + packageZclProtocol + ".ZclDataType");
+ importsAdd(packageRoot + packageZclProtocol + ".ZclClusterType");
+ }
+
+ if (!cluster.commands.isEmpty()) {
+ importsAdd(packageRoot + packageZcl + ".ZclCommand");
+ }
+ // imports.add(packageRoot + packageZcl + ".ZclCommandMessage");
+ importsAdd("javax.annotation.Generated");
+
+ // imports.add(packageRoot + ".ZigBeeDestination");
+ importsAdd(packageRoot + ".ZigBeeEndpoint");
+ if (!cluster.attributes.isEmpty() | !cluster.commands.isEmpty()) {
+ importsAdd(packageRoot + ".CommandResult");
+ importsAdd("java.util.concurrent.Future");
+ }
+ // imports.add(packageRoot + ".ZigBeeEndpoint");
+ importsAdd(packageRoot + packageZcl + ".ZclAttribute");
+ importsAdd("java.util.Map");
+ importsAdd("java.util.concurrent.ConcurrentHashMap");
+
+ outputImports(out);
+
+ out.println();
+ out.println("/**");
+ out.println(" * " + cluster.name + " cluster implementation (Cluster ID "
+ + String.format("0x%04X", cluster.code) + ").");
+ if (!cluster.description.isEmpty()) {
+ out.println(" * ");
+ outputWithLinebreak(out, "", cluster.description);
+ }
+
+ out.println(" *
");
+ out.println(" * Code is auto-generated. Modifications may be overwritten!");
+
+ out.println(" */");
+ // outputClassJavaDoc(out);
+ outputClassGenerated(out);
+ out.println("public class " + className + " extends ZclCluster {");
+
+ out.println(" /**");
+ out.println(" * The ZigBee Cluster Library Cluster ID");
+ out.println(" */");
+ out.println(" public static final int CLUSTER_ID = " + String.format("0x%04X;", cluster.code));
+ out.println();
+ out.println(" /**");
+ out.println(" * The ZigBee Cluster Library Cluster Name");
+ out.println(" */");
+ out.println(" public static final String CLUSTER_NAME = \"" + cluster.name + "\";");
+ out.println();
+
+ if (cluster.attributes.size() != 0) {
+ out.println(" // Attribute constants");
+ for (final ZigBeeXmlAttribute attribute : cluster.attributes) {
+ if (attribute.arrayStart != null && attribute.arrayCount != null && attribute.arrayCount > 0) {
+ int arrayCount = attribute.arrayStart;
+ int arrayStep = attribute.arrayStep == null ? 1 : attribute.arrayStep;
+ for (int count = 0; count < attribute.arrayCount; count++) {
+ if (!attribute.description.isEmpty()) {
+ out.println(" /**");
+ outputWithLinebreak(out, " ", attribute.description);
+ out.println(" */");
+ }
+ String name = attribute.name.replaceAll("\\{\\{count\\}\\}", Integer.toString(arrayCount));
+ out.println(" public static final int " + getEnum(name) + " = "
+ + String.format("0x%04X", attribute.code + arrayCount) + ";");
+ arrayCount += arrayStep;
+ }
+ } else {
+ if (!attribute.description.isEmpty()) {
+ out.println(" /**");
+ outputWithLinebreak(out, " ", attribute.description);
+ out.println(" */");
+ }
+ out.println(" public static final int " + getEnum(attribute.name) + " = "
+ + String.format("0x%04X", attribute.code) + ";");
+ }
+ }
+ out.println();
+ }
+
+ out.println(" // Attribute initialisation");
+ out.println(" @Override");
+ out.println(" protected Map initializeAttributes() {");
+ out.println(" Map attributeMap = new ConcurrentHashMap("
+ + attributesServer + ");");
+
+ if (attributesServer != 0) {
+ out.println();
+ for (final ZigBeeXmlAttribute attribute : cluster.attributes) {
+ if (!attribute.side.equalsIgnoreCase("server")) {
+ continue;
+ }
+
+ if (attribute.arrayStart != null && attribute.arrayCount != null && attribute.arrayCount > 0) {
+ int arrayCount = attribute.arrayStart;
+ int arrayStep = attribute.arrayStep == null ? 1 : attribute.arrayStep;
+ for (int count = 0; count < attribute.arrayCount; count++) {
+ String name = attribute.name.replaceAll("\\{\\{count\\}\\}", Integer.toString(arrayCount));
+ out.println(" attributeMap.put(" + getEnum(name) + ", "
+ + defineAttribute(attribute, cluster.name, name, 0) + ");");
+ arrayCount += arrayStep;
+ }
+ } else {
+ out.println(" attributeMap.put(" + getEnum(attribute.name) + ", "
+ + defineAttribute(attribute, cluster.name, attribute.name, 0) + ");");
+ }
+ }
+ }
+
+ // TODO: Add client attributes
+
+ out.println();
+ out.println(" return attributeMap;");
+ out.println(" }");
+ out.println();
+
+ out.println(" /**");
+ out.println(" * Default constructor to create a " + cluster.name + " cluster.");
+ out.println(" *");
+ out.println(" * @param zigbeeEndpoint the {@link ZigBeeEndpoint} this cluster is contained within");
+ out.println(" */");
+ out.println(" public " + className + "(final ZigBeeEndpoint zigbeeEndpoint) {");
+ out.println(" super(zigbeeEndpoint, CLUSTER_ID, CLUSTER_NAME);");
+ out.println(" }");
+
+ for (final ZigBeeXmlAttribute attribute : cluster.attributes) {
+ DataTypeMap zclDataType = ZclDataType.getDataTypeMapping().get(attribute.type);
+ if (zclDataType == null) {
+ throw new IllegalArgumentException(
+ "Unknown ZCL Type \"" + attribute.type + "\" for attribute \"" + attribute.name + "\".");
+ }
+
+ if (attribute.writable) {
+ outputAttributeJavaDoc(out, "Set", attribute, zclDataType);
+ if (attribute.arrayStart != null && attribute.arrayCount != null && attribute.arrayCount > 0) {
+ String name = attribute.name.replaceAll("\\{\\{count\\}\\}", "");
+ out.println(" public Future set" + stringToUpperCamelCase(name).replace("_", "")
+ + "(final int arrayOffset, final " + getDataTypeClass(attribute) + " value) {");
+ name = attribute.name.replaceAll("\\{\\{count\\}\\}", Integer.toString(attribute.arrayStart));
+ out.println(" return write(attributes.get(" + getEnum(name) + " + arrayOffset), value);");
+ } else {
+ out.println(" public Future set"
+ + stringToUpperCamelCase(attribute.name).replace("_", "") + "(final "
+ + getDataTypeClass(attribute) + " value) {");
+ out.println(" return write(attributes.get(" + getEnum(attribute.name) + "), value);");
+ }
+ out.println(" }");
+ }
+
+ // if (attribute.attributeAccess.toLowerCase().contains("read")) {
+ outputAttributeJavaDoc(out, "Get", attribute, zclDataType);
+ if (attribute.arrayStart != null && attribute.arrayCount != null && attribute.arrayCount > 0) {
+ String name = attribute.name.replaceAll("\\{\\{count\\}\\}", "");
+ out.println(" public Future get" + stringToUpperCamelCase(name).replace("_", "")
+ + "Async(final int arrayOffset) {");
+ out.println(" if (arrayOffset < " + attribute.arrayStart + " || arrayOffset > "
+ + (attribute.arrayStart + attribute.arrayCount - 1) + ") {");
+ out.println(" throw new IllegalArgumentException(\"arrayOffset out of bounds\");");
+ out.println(" }");
+ out.println();
+ name = attribute.name.replaceAll("\\{\\{count\\}\\}", Integer.toString(attribute.arrayStart));
+ out.println(" return read(attributes.get(" + getEnum(name) + " + arrayOffset));");
+ } else {
+ out.println(" public Future get"
+ + stringToUpperCamelCase(attribute.name).replace("_", "") + "Async() {");
+ out.println(" return read(attributes.get(" + getEnum(attribute.name) + "));");
+ }
+ out.println(" }");
+
+ // TODO: Needs to document the counter
+ outputAttributeJavaDoc(out, "Synchronously get", attribute, zclDataType);
+ if (attribute.arrayStart != null && attribute.arrayCount != null && attribute.arrayCount > 0) {
+ String name = attribute.name.replaceAll("\\{\\{count\\}\\}", "");
+ out.println(" public " + getDataTypeClass(attribute) + " get"
+ + stringToUpperCamelCase(name).replace("_", "")
+ + "(final int arrayOffset, final long refreshPeriod) {");
+ name = attribute.name.replaceAll("\\{\\{count\\}\\}", Integer.toString(attribute.arrayStart));
+ out.println(" if (attributes.get(" + getEnum(name) + " + arrayOffset"
+ + ").isLastValueCurrent(refreshPeriod)) {");
+ out.println(" return (" + getDataTypeClass(attribute) + ") attributes.get(" + getEnum(name)
+ + " + arrayOffset).getLastValue();");
+ out.println(" }");
+ out.println();
+ out.println(" return (" + getDataTypeClass(attribute) + ") readSync(attributes.get("
+ + getEnum(name) + " + arrayOffset));");
+ } else {
+ out.println(" public " + getDataTypeClass(attribute) + " get"
+ + stringToUpperCamelCase(attribute.name).replace("_", "") + "(final long refreshPeriod) {");
+ out.println(" if (attributes.get(" + getEnum(attribute.name)
+ + ").isLastValueCurrent(refreshPeriod)) {");
+ out.println(" return (" + getDataTypeClass(attribute) + ") attributes.get("
+ + getEnum(attribute.name) + ").getLastValue();");
+ out.println(" }");
+ out.println();
+ out.println(" return (" + getDataTypeClass(attribute) + ") readSync(attributes.get("
+ + getEnum(attribute.name) + "));");
+ }
+ out.println(" }");
+ // }
+
+ if (!attribute.optional) {
+ outputAttributeJavaDoc(out, "Set reporting for", attribute, zclDataType);
+ if (attribute.arrayStart != null && attribute.arrayCount != null && attribute.arrayCount > 0) {
+ String name = attribute.name.replaceAll("\\{\\{count\\}\\}",
+ Integer.toString(attribute.arrayStart));
+ String offset;
+ if (attribute.arrayStep == null) {
+ offset = "arrayOffset - 1";
+ } else {
+ offset = "(arrayOffset - 1) * " + attribute.arrayStep;
+ }
+
+ if (zclDataType.analogue) {
+ out.println(" public Future set" + stringToUpperCamelCase(name)
+ + "Reporting(final int arrayOffset, final int minInterval, final int maxInterval, final Object reportableChange) {");
+ out.println(" return setReporting(attributes.get(" + getEnum(name) + " + " + offset
+ + "), minInterval, maxInterval, reportableChange);");
+ } else {
+ out.println(" public Future set" + stringToUpperCamelCase(name)
+ + "Reporting(final int arrayOffset, final int minInterval, final int maxInterval) {");
+ out.println(" return setReporting(attributes.get(" + getEnum(name) + " + " + offset
+ + "), minInterval, maxInterval);");
+ }
+ } else {
+ if (zclDataType.analogue) {
+ out.println(" public Future set" + stringToUpperCamelCase(attribute.name)
+ + "Reporting(final int minInterval, final int maxInterval, final Object reportableChange) {");
+ out.println(" return setReporting(attributes.get(" + getEnum(attribute.name)
+ + "), minInterval, maxInterval, reportableChange);");
+ } else {
+ out.println(" public Future set" + stringToUpperCamelCase(attribute.name)
+ + "Reporting(final int minInterval, final int maxInterval) {");
+ out.println(" return setReporting(attributes.get(" + getEnum(attribute.name)
+ + "), minInterval, maxInterval);");
+ }
+ }
+ out.println(" }");
+ }
+ }
+
+ for (final ZigBeeXmlCommand command : cluster.commands) {
+ out.println();
+ out.println(" /**");
+ out.println(" * The " + command.name);
+ if (!command.description.isEmpty()) {
+ out.println(" * ");
+ outputWithLinebreak(out, " ", command.description);
+ }
+ out.println(" *");
+
+ final LinkedList fields = new LinkedList(command.fields);
+ for (final ZigBeeXmlField field : fields) {
+ out.println(" * @param " + stringToLowerCamelCase(field.name) + " {@link " + getDataTypeClass(field)
+ + "} " + field.name);
+ }
+
+ out.println(" * @return the {@link Future} command result future");
+ out.println(" */");
+ out.print(" public Future " + stringToLowerCamelCase(command.name) + "(");
+
+ boolean first = true;
+ for (final ZigBeeXmlField field : fields) {
+ if (first == false) {
+ out.print(", ");
+ }
+ out.print(getDataTypeClass(field) + " " + stringToLowerCamelCase(field.name));
+ first = false;
+ }
+
+ out.println(") {");
+ if (fields.size() == 0) {
+ out.println(" return send(new " + stringToUpperCamelCase(command.name) + "());");
+ } else {
+ out.println(" " + stringToUpperCamelCase(command.name) + " command = new "
+ + stringToUpperCamelCase(command.name) + "();");
+ out.println();
+ out.println(" // Set the fields");
+
+ for (final ZigBeeXmlField field : fields) {
+ out.println(" command.set" + stringToUpperCamelCase(field.name) + "("
+ + stringToLowerCamelCase(field.name) + ");");
+ }
+ out.println();
+ out.println(" return send(command);");
+ }
+ out.println(" }");
+ }
+
+ if (commandsServer > 0) {
+ out.println();
+ out.println(" @Override");
+ out.println(" public ZclCommand getCommandFromId(int commandId) {");
+ out.println(" switch (commandId) {");
+ for (final ZigBeeXmlCommand command : cluster.commands) {
+ if (command.source.equalsIgnoreCase("client")) {
+ out.println(" case 0x" + String.format("%02X", command.code) + ": // "
+ + stringToConstant(command.name));
+ out.println(" return new " + stringToUpperCamelCase(command.name) + "();");
+ }
+ }
+ out.println(" default:");
+ out.println(" return null;");
+ out.println(" }");
+ out.println(" }");
+ }
+
+ if (commandsClient > 0) {
+ out.println();
+ out.println(" @Override");
+ out.println(" public ZclCommand getResponseFromId(int commandId) {");
+ out.println(" switch (commandId) {");
+ for (final ZigBeeXmlCommand command : cluster.commands) {
+ if (command.source.equalsIgnoreCase("server")) {
+ out.println(" case 0x" + String.format("%02X", command.code) + ": // "
+ + stringToConstant(command.name));
+ out.println(" return new " + stringToUpperCamelCase(command.name) + "();");
+ }
+ }
+ out.println(" default:");
+ out.println(" return null;");
+ out.println(" }");
+ out.println(" }");
+ }
+
+ out.println("}");
+
+ out.flush();
+ out.close();
+ }
+
+ private String defineAttribute(ZigBeeXmlAttribute attribute, String clusterName, String attributeName, int count) {
+ return "new ZclAttribute(ZclClusterType." + stringToConstant(clusterName) + ", " + getEnum(attributeName)
+ + ", \"" + attributeName + "\", " + "ZclDataType." + attribute.type + ", " + !attribute.optional + ", "
+ + true + ", " + attribute.writable + ", " + attribute.reportable + ")";
+ }
+
+ private String getEnum(String name) {
+ return "ATTR_" + stringToConstantEnum(name);
+ }
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclClusterTypeGenerator.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclClusterTypeGenerator.java
new file mode 100644
index 000000000..cd2dfce7a
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclClusterTypeGenerator.java
@@ -0,0 +1,138 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlCluster;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeZclClusterTypeGenerator extends ZigBeeBaseClassGenerator {
+ ZigBeeZclClusterTypeGenerator(String sourceRootPath, String licenseText, List clusters, String generatedDate,
+ Map dependencies) {
+ super(sourceRootPath, licenseText);
+ this.generatedDate = generatedDate;
+ this.dependencies = dependencies;
+
+ try {
+ generateZclClusterCommands(clusters, packageRoot, new File(sourceRootPath));
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private void generateZclClusterCommands(List clusters, String packageRootPrefix,
+ File sourceRootPath) throws IOException {
+
+ final String className = "ZclClusterType";
+
+ final String packageRoot = packageRootPrefix + packageZclProtocol;
+ final String packagePath = getPackagePath(sourceRootPath, packageRoot);
+ final File packageFile = getPackageFile(packagePath);
+
+ final PrintWriter out = getClassOut(packageFile, className);
+
+ outputLicense(out);
+ importsClear();
+
+ Map clusterEnum = new TreeMap<>();
+ for (final ZigBeeXmlCluster cluster : clusters) {
+ // Suppress GENERAL cluster as it's not really a cluster!
+ if (cluster.name.equalsIgnoreCase("GENERAL")) {
+ continue;
+ }
+ clusterEnum.put(cluster.code, cluster);
+ importsAdd(
+ packageRootPrefix + packageZclCluster + ".Zcl" + stringToUpperCamelCase(cluster.name) + "Cluster");
+ }
+
+ out.println("package " + packageRoot + ";");
+ out.println();
+ importsAdd(packageRootPrefix + packageZcl + ".ZclCluster");
+ importsAdd("java.util.Map");
+ importsAdd("java.util.concurrent.ConcurrentHashMap");
+ importsAdd("javax.annotation.Generated");
+ outputImports(out);
+ out.println();
+ out.println("/**");
+ out.println(" * Enumeration of ZigBee Clusters\n" + " * \n"
+ + " * Code is auto-generated. Modifications may be overwritten!\n" + " *\n"
+ + " * @author Chris Jackson\n");
+ out.println(" */");
+ outputClassGenerated(out);
+ out.println("public enum " + className + " {");
+
+ boolean first = true;
+ for (final ZigBeeXmlCluster cluster : clusterEnum.values()) {
+ if (first == false) {
+ out.println(",");
+ }
+ first = false;
+ out.print(" " + stringToConstant(cluster.name) + "(" + String.format("0x%04X", cluster.code) + ", Zcl"
+ + stringToUpperCamelCase(cluster.name) + "Cluster.class, \"" + cluster.name + "\")");
+ }
+ out.println(";");
+
+ out.println();
+ out.println(" private static final Map idValueMap = new ConcurrentHashMap<>();");
+ out.println();
+ out.println(" private final int clusterId;");
+ out.println(" private final String label;");
+ out.println(" private final Class extends ZclCluster> clusterClass;");
+ out.println();
+ out.println(" " + className
+ + "(final int clusterId, final Class extends ZclCluster>clusterClass, final String label) {");
+ out.println(" this.clusterId = clusterId;");
+ out.println(" this.clusterClass = clusterClass;");
+ out.println(" this.label = label;");
+ out.println(" }");
+ out.println();
+ out.println(" static {");
+ out.println(" for (final ZclClusterType value : values()) {");
+ out.println(" idValueMap.put(value.clusterId, value);");
+ out.println(" }");
+ out.println(" }");
+ out.println();
+ out.println(" public int getId() {");
+ out.println(" return clusterId;");
+ out.println(" }");
+ out.println();
+ out.println(" public String getLabel() {");
+ out.println(" return label;");
+ out.println(" }");
+ out.println();
+ // out.println(" public String toString() {");
+ // out.println(" return label;");
+ // out.println(" }");
+ // out.println();
+ out.println(" public Class extends ZclCluster> getClusterClass() {");
+ out.println(" return clusterClass;");
+ out.println(" }");
+ out.println();
+ out.println(" public static ZclClusterType getValueById(final int clusterId) {");
+ out.println(" return idValueMap.get(clusterId);");
+ out.println(" }");
+ out.println();
+ out.println("}");
+
+ out.flush();
+ out.close();
+
+ }
+
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclCommandGenerator.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclCommandGenerator.java
new file mode 100644
index 000000000..470f3c1a1
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclCommandGenerator.java
@@ -0,0 +1,240 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlCluster;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlCommand;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlField;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlMatcher;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeZclCommandGenerator extends ZigBeeBaseFieldGenerator {
+
+ ZigBeeZclCommandGenerator(String sourceRootPath, String licenseText, List clusters, String generatedDate, Map dependencies) {
+ super(sourceRootPath, licenseText);
+ this.generatedDate = generatedDate;
+ this.dependencies = dependencies;
+
+ for (ZigBeeXmlCluster cluster : clusters) {
+ try {
+ generateZclClusterCommands(cluster, packageRoot, new File(sourceRootPath));
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void generateZclClusterCommands(ZigBeeXmlCluster cluster, String packageRootPrefix, File sourceRootPath)
+ throws IOException {
+
+ for (final ZigBeeXmlCommand command : cluster.commands) {
+ final String packageRoot = getZclClusterCommandPackage(cluster);
+ final String packagePath = getPackagePath(sourceRootPath, packageRoot);
+ final File packageFile = getPackageFile(packagePath);
+
+ final String className = stringToUpperCamelCase(command.name);
+ final PrintWriter out = getClassOut(packageFile, className);
+
+ // List of fields that are handled internally by super class
+ List reservedFields = new ArrayList<>();
+
+ importsClear();
+
+ for (final ZigBeeXmlField field : command.fields) {
+ if (getDataTypeClass(field).startsWith("List")) {
+ importsAdd("java.util.List");
+ }
+
+ if (field.sizer != null) {
+ importsAdd("java.util.ArrayList");
+ }
+ }
+ outputLicense(out);
+
+ out.println("package " + packageRoot + ";");
+ out.println();
+ importsAdd("javax.annotation.Generated");
+
+ if (command.response != null) {
+ importsAdd(packageRootPrefix + ".transaction.ZigBeeTransactionMatcher");
+ importsAdd(packageRootPrefix + ".ZigBeeCommand");
+
+ importsAdd(packageRoot + "." + command.response.command);
+ }
+
+ String commandExtends = "";
+ if (packageRoot.contains(".zcl.")) {
+ importsAdd(packageRootPrefix + packageZcl + ".ZclCommand");
+ importsAdd(packageRootPrefix + packageZclProtocol + ".ZclCommandDirection");
+ commandExtends = "ZclCommand";
+ } else {
+ if (command.name.contains("Response")) {
+ commandExtends = "ZdoResponse";
+ reservedFields.add("status");
+ } else {
+ commandExtends = "ZdoRequest";
+ }
+ importsAdd(packageRootPrefix + packageZdp + "." + commandExtends);
+ }
+
+ if (command.fields.size() > 0) {
+ importsAdd(packageRootPrefix + packageZcl + ".ZclFieldSerializer");
+ importsAdd(packageRootPrefix + packageZcl + ".ZclFieldDeserializer");
+ importsAdd(packageRootPrefix + packageZclProtocol + ".ZclDataType");
+ }
+
+ for (final ZigBeeXmlField field : command.fields) {
+ importsAddClass(field);
+ }
+ outputImports(out);
+
+ out.println();
+ out.println("/**");
+ out.println(" * " + command.name + " value object class.");
+
+ out.println(" * ");
+ if (packageRoot.contains(".zcl.")) {
+ out.println(" * Cluster: " + cluster.name + ". Command is sent "
+ + (command.source.equals("client") ? "TO" : "FROM") + " the server.");
+ out.println(" * This command is " + ((cluster.name.equalsIgnoreCase("GENERAL"))
+ ? "a generic command used across the profile."
+ : "a specific command used for the " + cluster.name + " cluster."));
+ }
+
+ if (command.description.size() > 0) {
+ out.println(" *
");
+ outputWithLinebreak(out, "", command.description);
+ }
+
+ out.println(" *
");
+ out.println(" * Code is auto-generated. Modifications may be overwritten!");
+
+ out.println(" */");
+ outputClassGenerated(out);
+ out.print("public class " + className + " extends " + commandExtends);
+ if (command.response != null) {
+ out.print(" implements ZigBeeTransactionMatcher");
+ }
+ out.println(" {");
+
+ for (final ZigBeeXmlField field : command.fields) {
+ if (reservedFields.contains(stringToLowerCamelCase(field.name))) {
+ continue;
+ }
+ if (getAutoSized(command.fields, stringToLowerCamelCase(field.name)) != null) {
+ continue;
+ }
+
+ out.println(" /**");
+ out.println(" * " + field.name + " command message field.");
+ if (field.description.size() != 0) {
+ out.println(" *
");
+ outputWithLinebreak(out, " ", field.description);
+ }
+ out.println(" */");
+ out.println(" private " + getDataTypeClass(field) + " " + stringToLowerCamelCase(field.name) + ";");
+ out.println();
+ }
+
+ out.println(" /**");
+ out.println(" * Default constructor.");
+ out.println(" */");
+ out.println(" public " + className + "() {");
+ if (commandExtends.equals("ZclCommand")) {
+ out.println(" genericCommand = "
+ + ((cluster.name.equalsIgnoreCase("GENERAL")) ? "true" : "false") + ";");
+
+ if (!cluster.name.equalsIgnoreCase("GENERAL")) {
+ out.println(" clusterId = 0x" + String.format("%04X", cluster.code) + ";");
+ }
+
+ out.println(" commandId = " + command.code + ";");
+ out.println(" commandDirection = ZclCommandDirection."
+ + (command.source.equals("client") ? "CLIENT_TO_SERVER" : "SERVER_TO_CLIENT") + ";");
+ } else {
+ out.println(" clusterId = 0x" + String.format("%04X", command.code) + ";");
+ }
+ out.println(" }");
+
+ if (cluster.name.equalsIgnoreCase("GENERAL")) {
+ out.println();
+ out.println(" /**");
+ out.println(" * Sets the cluster ID for generic commands. {@link " + className
+ + "} is a generic command.");
+ out.println(" *
");
+ out.println(
+ " * For commands that are not generic, this method will do nothing as the cluster ID is fixed.");
+ out.println(" * To test if a command is generic, use the {@link #isGenericCommand} method.");
+ out.println(" *");
+ out.println(
+ " * @param clusterId the cluster ID used for generic commands as an {@link Integer}");
+
+ out.println(" */");
+ out.println(" @Override");
+ out.println(" public void setClusterId(Integer clusterId) {");
+ out.println(" this.clusterId = clusterId;");
+ out.println(" }");
+ }
+
+ generateFields(out, commandExtends, className, command.fields, reservedFields);
+
+ if (command.response != null) {
+ out.println();
+ out.println(" @Override");
+ out.println(" public boolean isTransactionMatch(ZigBeeCommand request, ZigBeeCommand response) {");
+ if (command.response.matchers.isEmpty()) {
+ out.println(" return (response instanceof " + command.response.command + ")");
+ out.println(" & ((ZdoRequest) request).getDestinationAddress().equals((("
+ + command.response.command + ") response).getSourceAddress());");
+ } else {
+ out.println(" if (!(response instanceof " + command.response.command + ")) {");
+ out.println(" return false;");
+ out.println(" }");
+ out.println();
+ out.print(" return ");
+
+ boolean first = true;
+ for (ZigBeeXmlMatcher matcher : command.response.matchers) {
+ if (first == false) {
+ out.println();
+ out.print(" && ");
+ }
+ first = false;
+ out.println("(((" + stringToUpperCamelCase(command.name) + ") request).get"
+ + matcher.commandField + "()");
+ out.print(" .equals(((" + command.response.command + ") response).get"
+ + matcher.responseField + "()))");
+ }
+ out.println(";");
+ }
+ out.println(" }");
+ }
+
+ generateToString(out, className, command.fields, reservedFields);
+
+ out.println();
+ out.println("}");
+
+ out.flush();
+ out.close();
+ }
+ }
+
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclCommandTypeGenerator.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclCommandTypeGenerator.java
new file mode 100644
index 000000000..d81cfb143
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclCommandTypeGenerator.java
@@ -0,0 +1,189 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlCluster;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlCommand;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeZclCommandTypeGenerator extends ZigBeeBaseClassGenerator {
+
+ ZigBeeZclCommandTypeGenerator(String sourceRootPath, String licenseText, List clusters, String generatedDate,
+ Map dependencies) {
+ super(sourceRootPath, licenseText);
+ this.generatedDate = generatedDate;
+ this.dependencies = dependencies;
+
+ try {
+ generateZclClusterCommands(clusters, packageRoot, new File(sourceRootPath));
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private void generateZclClusterCommands(List clusters, String packageRootPrefix,
+ File sourceRootPath) throws IOException {
+
+ final String className = "ZclCommandType";
+
+ final String packageRoot = packageRootPrefix + packageZclProtocol;
+ final String packagePath = getPackagePath(sourceRootPath, packageRoot);
+ final File packageFile = getPackageFile(packagePath);
+
+ final PrintWriter out = getClassOut(packageFile, className);
+
+ Map commandEnum = new TreeMap<>();
+
+ outputLicense(out);
+
+ importsClear();
+ out.println("package " + packageRoot + ";");
+ out.println();
+ importsAdd("javax.annotation.Generated");
+ importsAdd("java.lang.reflect.Constructor");
+ importsAdd(packageRootPrefix + packageZcl + ".ZclCommand");
+ importsAdd(packageRootPrefix + packageZclProtocol + ".ZclCommandDirection");
+
+ // Produce an ordered list of clusters/commands and add the imports...
+ for (final ZigBeeXmlCluster cluster : clusters) {
+ for (ZigBeeXmlCommand command : cluster.commands) {
+ importsAdd(getZclClusterCommandPackage(cluster) + "." + stringToUpperCamelCase(command.name));
+ commandEnum.put(getZclClusterCommandPackage(cluster) + "." + stringToUpperCamelCase(command.name),
+ new CommandId(cluster, command));
+ }
+ }
+
+ outputImports(out);
+ out.println();
+
+ // outputClassJavaDoc(out, "Enumeration of ZigBee Cluster Library commands");
+ outputClassGenerated(out);
+ out.println("public enum " + className + " {");
+ boolean first = true;
+ for (CommandId commandId : commandEnum.values()) {
+ ZigBeeXmlCluster cluster = commandId.cluster;
+ ZigBeeXmlCommand command = commandId.command;
+ if (!first) {
+ out.println(",");
+ }
+ first = false;
+
+ String commandType = stringToConstant(command.name);
+ String commandClass = stringToUpperCamelCase(command.name);
+ out.println(" /**");
+ out.println(" * " + commandType + ": " + command.name);
+ out.println(" * ");
+ out.println(" * See {@link " + commandClass + "}");
+ out.println(" */");
+
+ out.print(" " + commandType + "(" + String.format("0x%04X", cluster.code) + ", " + command.code + ", "
+ + commandClass + ".class" + ", ZclCommandDirection."
+ + (command.source.equals("client") ? "CLIENT_TO_SERVER" : "SERVER_TO_CLIENT") + ")");
+ }
+ out.println(";");
+ out.println();
+
+ out.println(" private final int commandId;");
+ out.println(" private final int clusterType;");
+ out.println(" private final Class extends ZclCommand> commandClass;");
+ // out.println(" private final String label;");
+ out.println(" private final ZclCommandDirection direction;");
+ out.println();
+ out.println(" " + className
+ + "(final int clusterType, final int commandId, final Class extends ZclCommand> commandClass, final ZclCommandDirection direction) {");
+ out.println(" this.clusterType = clusterType;");
+ out.println(" this.commandId = commandId;");
+ out.println(" this.commandClass = commandClass;");
+ // out.println(" this.label = label;");
+ out.println(" this.direction = direction;");
+ out.println(" }");
+ out.println();
+
+ out.println(" public int getClusterType() {");
+ out.println(" return clusterType;");
+ out.println(" }");
+ out.println();
+ out.println(" public int getId() {");
+ out.println(" return commandId;");
+ out.println(" }");
+ out.println();
+ // out.println(" public String getLabel() { return label; }");
+ out.println(" public boolean isGeneric() {");
+ out.println(" return clusterType==0xFFFF;");
+ out.println(" }");
+ out.println();
+ out.println(" public ZclCommandDirection getDirection() {");
+ out.println(" return direction;");
+ out.println(" }");
+ out.println();
+ out.println(" public Class extends ZclCommand> getCommandClass() {");
+ out.println(" return commandClass;");
+ out.println(" }");
+ out.println();
+ out.println(
+ " public static ZclCommandType getCommandType(final int clusterType, final int commandId,\n");
+ out.println(" ZclCommandDirection direction) {\n");
+ out.println(" for (final ZclCommandType value : values()) {\n");
+ out.println(
+ " if (value.direction == direction && value.clusterType == clusterType && value.commandId == commandId) {\n");
+ out.println(" return value;\n");
+ out.println(" }\n");
+ out.println(" }\n");
+ out.println(" return null;\n");
+ out.println(" }");
+
+ out.println();
+ out.println(" public static ZclCommandType getGeneric(final int commandId) {");
+ out.println(" for (final ZclCommandType value : values()) {");
+ out.println(" if (value.clusterType == 0xFFFF && value.commandId == commandId) {");
+ out.println(" return value;");
+ out.println(" }");
+ out.println(" }");
+ out.println(" return null;");
+ out.println(" }");
+
+ out.println();
+ out.println(" public ZclCommand instantiateCommand() {");
+ out.println(" Constructor extends ZclCommand> cmdConstructor;");
+ out.println(" try {");
+ out.println(" cmdConstructor = commandClass.getConstructor();");
+ out.println(" return cmdConstructor.newInstance();");
+ out.println(" } catch (Exception e) {");
+ out.println(" // logger.debug(\"Error instantiating cluster command {}\", this);");
+ out.println(" }");
+ out.println(" return null;");
+ out.println(" }");
+
+ out.println("}");
+
+ out.flush();
+ out.close();
+ }
+
+ private class CommandId {
+ ZigBeeXmlCluster cluster;
+ ZigBeeXmlCommand command;
+
+ public CommandId(ZigBeeXmlCluster cluster, ZigBeeXmlCommand command) {
+ this.cluster = cluster;
+ this.command = command;
+ }
+ }
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclConstantGenerator.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclConstantGenerator.java
new file mode 100644
index 000000000..3ccd02319
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclConstantGenerator.java
@@ -0,0 +1,163 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlCluster;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlConstant;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeZclConstantGenerator extends ZigBeeBaseClassGenerator {
+
+ ZigBeeZclConstantGenerator(String sourceRootPath, String licenseText, List clusters, String generatedDate,
+ Map dependencies) {
+ super(sourceRootPath, licenseText);
+ this.generatedDate = generatedDate;
+ this.dependencies = dependencies;
+
+ for (ZigBeeXmlCluster cluster : clusters) {
+ try {
+ generateZclClusterConstants(cluster, packageRoot, new File(sourceRootPath));
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ ZigBeeZclConstantGenerator(String sourceRootPath, String licenseText, ZigBeeXmlConstant constant, String generatedDate) {
+ super(sourceRootPath, licenseText);
+ this.generatedDate = generatedDate;
+ String packageRoot = "com.zsmartsystems.zigbee";
+
+ try {
+ generateZclConstant(new File(sourceRootPath), packageRoot, constant);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private void generateZclClusterConstants(ZigBeeXmlCluster cluster, String packageRootPrefix, File sourceRootPath)
+ throws IOException {
+ if (cluster.constants == null) {
+ return;
+ }
+
+ for (final ZigBeeXmlConstant constant : cluster.constants) {
+ final String packageRoot = packageRootPrefix + packageZclProtocolCommand + "."
+ + stringToLowerCamelCase(cluster.name).replace("_", "").toLowerCase();
+
+ generateZclConstant(sourceRootPath, packageRoot, constant);
+ }
+ }
+
+ private void generateZclConstant(File sourceRootPath, String packageRoot, ZigBeeXmlConstant constant)
+ throws FileNotFoundException {
+ final String packagePath = getPackagePath(sourceRootPath, packageRoot);
+ final File packageFile = getPackageFile(packagePath);
+
+ final String className = constant.className;
+ final PrintWriter out = getClassOut(packageFile, className);
+
+ outputLicense(out);
+
+ importsClear();
+ out.println("package " + packageRoot + ";");
+ out.println();
+
+ importsAdd("javax.annotation.Generated");
+ importsAdd("java.util.HashMap");
+ importsAdd("java.util.Map");
+
+ outputImports(out);
+
+ out.println("/**");
+ out.println(" * " + constant.name + " value enumeration.");
+
+ if (constant.description.size() > 0) {
+ out.println(" * ");
+ outputWithLinebreak(out, "", constant.description);
+ }
+
+ out.println(" *
");
+ out.println(" * Code is auto-generated. Modifications may be overwritten!");
+
+ out.println(" */");
+ outputClassGenerated(out);
+ out.println("public enum " + className + " {");
+
+ boolean first = true;
+ for (final Entry value : constant.values.entrySet()) {
+ if (!first) {
+ out.println(",");
+ }
+ first = false;
+
+ out.println();
+ out.println(" /**");
+ out.println(" * " + value.getValue());
+ // if (constant.description.size() != 0) {
+ // out.println(" * ");
+ // outputWithLinebreak(out, " ", constant.description);
+ // }
+ out.println(" */");
+ out.print(
+ " " + stringToConstant(value.getValue()) + "(0x" + String.format("%04X", value.getKey()) + ")");
+ }
+ out.println(";");
+
+ out.println();
+
+ out.println(" /**");
+ out.println(" * A mapping between the integer code and its corresponding " + className
+ + " type to facilitate lookup by value.");
+ out.println(" */");
+ out.println(" private static Map idMap;");
+ out.println();
+ out.println(" static {");
+ out.println(" idMap = new HashMap();");
+ out.println(" for (" + className + " enumValue : values()) {");
+ out.println(" idMap.put(enumValue.key, enumValue);");
+ out.println(" }");
+ out.println(" }");
+ out.println();
+ out.println(" private final int key;");
+ out.println();
+ out.println(" private " + className + "(final int key) {");
+ out.println(" this.key = key;");
+ out.println(" }");
+ out.println();
+
+ out.println(" public int getKey() {");
+ out.println(" return key;");
+ out.println(" }");
+ out.println();
+ out.println(" public static " + className + " getByValue(final int value) {");
+ out.println(" return idMap.get(value);");
+ out.println(" }");
+
+ out.println("}");
+
+ out.flush();
+ out.close();
+ }
+
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclDataTypeGenerator.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclDataTypeGenerator.java
new file mode 100644
index 000000000..7e81e406a
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclDataTypeGenerator.java
@@ -0,0 +1,169 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import com.zsmartsystems.zigbee.autocode.ZclDataType.DataTypeMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author Chris Jackson
+ *
+ */
+public class ZigBeeZclDataTypeGenerator extends ZigBeeBaseClassGenerator {
+ private final Logger log = LoggerFactory.getLogger(ZigBeeZclDataTypeGenerator.class);
+
+ ZigBeeZclDataTypeGenerator(String sourceRootPath, String licenseText, Set types, String generatedDate) {
+ super(sourceRootPath, licenseText);
+ try {
+ this.generatedDate = generatedDate;
+ generateZclDataTypeEnumeration(types);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void generateZclDataTypeEnumeration(Set dataTypes) throws IOException {
+ final String className = "ZclDataType";
+
+ dataTypes.add("EXTENDED_PANID");
+ dataTypes.add("UNSIGNED_8_BIT_INTEGER_ARRAY");
+ dataTypes.add("ZIGBEE_DATA_TYPE");
+
+ List sortedTypes = new LinkedList<>();
+ sortedTypes.addAll(dataTypes);
+ Collections.sort(sortedTypes);
+
+ final String packagePath = getPackagePath(new File(sourceRootPath), packageRoot + packageZclProtocol);
+ final File packageFile = getPackageFile(packagePath);
+
+ final PrintWriter out = getClassOut(packageFile, className);
+ outputLicense(out);
+
+ importsClear();
+ out.println("package " + packageRoot + packageZclProtocol + ";");
+ out.println();
+
+ importsAdd("javax.annotation.Generated");
+ importsAdd("java.util.Calendar");
+ importsAdd("java.util.HashMap");
+ importsAdd("java.util.Map");
+ importsAdd("com.zsmartsystems.zigbee.ExtendedPanId");
+ importsAdd("com.zsmartsystems.zigbee.IeeeAddress");
+ importsAdd("com.zsmartsystems.zigbee.zcl.ZclStatus");
+ importsAdd("com.zsmartsystems.zigbee.zcl.field.ByteArray");
+ importsAdd("com.zsmartsystems.zigbee.zcl.field.ExtensionFieldSet");
+ importsAdd("com.zsmartsystems.zigbee.zcl.field.AttributeInformation");
+ importsAdd("com.zsmartsystems.zigbee.zcl.field.AttributeRecord");
+ importsAdd("com.zsmartsystems.zigbee.zcl.field.AttributeReport");
+ importsAdd("com.zsmartsystems.zigbee.zcl.field.NeighborInformation");
+ importsAdd("com.zsmartsystems.zigbee.zcl.field.AttributeReportingConfigurationRecord");
+ importsAdd("com.zsmartsystems.zigbee.zcl.field.AttributeStatusRecord");
+ importsAdd("com.zsmartsystems.zigbee.zcl.field.ExtendedAttributeInformation");
+ importsAdd("com.zsmartsystems.zigbee.zcl.field.ReadAttributeStatusRecord");
+ importsAdd("com.zsmartsystems.zigbee.zcl.field.WriteAttributeRecord");
+ importsAdd("com.zsmartsystems.zigbee.zcl.field.WriteAttributeStatusRecord");
+ importsAdd("com.zsmartsystems.zigbee.zdo.ZdoStatus");
+ importsAdd("com.zsmartsystems.zigbee.zdo.field.BindingTable");
+ importsAdd("com.zsmartsystems.zigbee.zdo.field.ComplexDescriptor");
+ importsAdd("com.zsmartsystems.zigbee.zdo.field.NeighborTable");
+ importsAdd("com.zsmartsystems.zigbee.zdo.field.NodeDescriptor");
+ importsAdd("com.zsmartsystems.zigbee.zdo.field.PowerDescriptor");
+ importsAdd("com.zsmartsystems.zigbee.zdo.field.RoutingTable");
+ importsAdd("com.zsmartsystems.zigbee.zdo.field.SimpleDescriptor");
+ importsAdd("com.zsmartsystems.zigbee.zdo.field.UserDescriptor");
+
+ outputImports(out);
+
+ out.println();
+ out.println("/**");
+ out.println(" * Enumeration of the ZCL data types.");
+ out.println(" * ");
+ out.println(" * Code is auto-generated. Modifications may be overwritten!");
+ out.println(" */");
+ outputClassGenerated(out);
+
+ out.println("public enum " + className + " {");
+
+ boolean first = true;
+ for (final String dataTypeString : sortedTypes) {
+ DataTypeMap zclDataType = ZclDataType.getDataTypeMapping().get(dataTypeString);
+ if (zclDataType == null) {
+ log.warn("Unable to map data type \"{}\"", dataTypeString);
+ continue;
+ }
+
+ if (!first) {
+ out.println(',');
+ }
+ first = false;
+
+ final String dataTypeClass;
+ if (zclDataType.dataClass.contains("<")) {
+ dataTypeClass = zclDataType.dataClass.substring(zclDataType.dataClass.indexOf("<") + 1,
+ zclDataType.dataClass.indexOf(">"));
+ } else {
+ dataTypeClass = zclDataType.dataClass;
+ }
+ out.print(" " + dataTypeString + "(" + dataTypeClass + ".class" + ", "
+ + String.format("0x%02X", zclDataType.id) + ", " + zclDataType.analogue + ")");
+ }
+ out.println(';');
+
+ out.println();
+ out.println(" private final Class> dataClass;");
+ out.println(" private final int typeId;");
+ out.println(" private final boolean analogue;");
+ out.println(" private static Map codeTypeMapping;");
+ out.println();
+
+ out.println(" static {");
+ out.println(" codeTypeMapping = new HashMap();");
+ out.println(" for (" + className + " value : values()) {");
+ out.println(" codeTypeMapping.put(value.typeId, value);");
+ out.println(" }");
+ out.println(" }");
+ out.println();
+ out.println(" " + className + "(final Class> dataClass, final int typeId, final boolean analogue) {");
+ out.println(" this.dataClass = dataClass;");
+ out.println(" this.typeId = typeId;");
+ out.println(" this.analogue = analogue;");
+ out.println(" }");
+ out.println();
+
+ out.println(" public static " + className + " getType(int typeId) {");
+ out.println(" return codeTypeMapping.get(typeId);");
+ out.println(" }");
+
+ out.println();
+ out.println(" public Class> getDataClass() {");
+ out.println(" return dataClass;");
+ out.println(" }");
+ out.println();
+ out.println(" public int getId() {");
+ out.println(" return typeId;");
+ out.println(" }");
+ out.println();
+ out.println(" public boolean isAnalog() {");
+ out.println(" return analogue;");
+ out.println(" }");
+ out.println("}");
+
+ out.flush();
+ out.close();
+ }
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclDependencyGenerator.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclDependencyGenerator.java
new file mode 100644
index 000000000..dbb8b4d90
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclDependencyGenerator.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode;
+
+import com.zsmartsystems.zigbee.autocode.xml.*;
+
+import java.util.*;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeZclDependencyGenerator extends ZigBeeBaseClassGenerator {
+
+ private Map dependencies = new HashMap<>();
+ private Set zclTypes = new HashSet<>();
+
+ ZigBeeZclDependencyGenerator(String sourceRootPath, String licenseText, List clusters) {
+ super(sourceRootPath, licenseText);
+ for (ZigBeeXmlCluster cluster : clusters) {
+ generateZclClusterDependencies(cluster, packageRoot);
+ }
+ }
+
+ private void generateZclClusterDependencies(ZigBeeXmlCluster cluster, String packageRootPrefix) {
+ if (cluster.constants != null) {
+ for (final ZigBeeXmlConstant constant : cluster.constants) {
+ final String packageRoot = packageRootPrefix + packageZclProtocolCommand + "."
+ + stringToLowerCamelCase(cluster.name).replace("_", "").toLowerCase();
+
+ final String className = constant.className;
+
+ String lastClass = dependencies.put(className, packageRoot + "." + className);
+ if (lastClass != null) {
+ throw new IllegalStateException(
+ "Duplicate class definition: " + lastClass + " with " + packageRoot + "." + className);
+ }
+ }
+ }
+
+ if (cluster.structures != null) {
+ for (final ZigBeeXmlStructure structure : cluster.structures) {
+ final String packageRoot = packageRootPrefix + packageZclProtocolCommand + "."
+ + stringToLowerCamelCase(cluster.name).replace("_", "").toLowerCase();
+
+ final String className = structure.className;
+
+ String lastClass = dependencies.put(className, packageRoot + "." + className);
+ if (lastClass != null) {
+ throw new IllegalStateException(
+ "Duplicate class definition: " + lastClass + " with " + packageRoot + "." + className);
+ }
+
+ for (ZigBeeXmlField field : structure.fields) {
+ zclTypes.add(field.type);
+ }
+ }
+ }
+
+ if (cluster.commands != null) {
+ for (final ZigBeeXmlCommand command : cluster.commands) {
+ for (ZigBeeXmlField field : command.fields) {
+ zclTypes.add(field.type);
+ }
+ }
+ }
+
+ if (cluster.attributes != null) {
+ for (ZigBeeXmlAttribute attribute : cluster.attributes) {
+ zclTypes.add(attribute.type);
+ }
+ }
+
+ }
+
+ public Map getDependencyMap() {
+ return dependencies;
+ }
+
+ public Set getZclTypeMap() {
+ return zclTypes;
+ }
+
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclReadmeGenerator.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclReadmeGenerator.java
new file mode 100644
index 000000000..409e8c73b
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclReadmeGenerator.java
@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.List;
+
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlCluster;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeZclReadmeGenerator extends ZigBeeBaseClassGenerator {
+ final String TABLE1 = "| ID | Cluster | Description |";
+ final String TABLE2 = "|----|---------|-------------|";
+ final String README_MD = "../README.md";
+
+ ZigBeeZclReadmeGenerator(String sourceRootPath, String licenseText, List clusters) {
+ super(sourceRootPath, licenseText);
+ FileInputStream fstream;
+ try {
+ fstream = new FileInputStream(README_MD);
+ BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
+ String strLine;
+ String mdContents = "";
+
+ // Read File Line By Line
+ while ((strLine = br.readLine()) != null) {
+ if (strLine.equals(TABLE1)) {
+ while ((strLine = br.readLine()) != null) {
+ if (!strLine.startsWith("|")) {
+ break;
+ }
+ }
+ mdContents += writeTable(clusters);
+ mdContents += strLine + "\n";
+
+ continue;
+ }
+
+ mdContents += strLine + "\n";
+ }
+
+ // Close the input stream
+ fstream.close();
+
+ PrintWriter fos;
+
+ fos = new PrintWriter(README_MD);
+ fos.print(mdContents);
+ fos.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ private String writeTable(List clusters) {
+ String mdContents = "";
+ mdContents += TABLE1 + "\n";
+ mdContents += TABLE2 + "\n";
+ for (ZigBeeXmlCluster cluster : clusters) {
+ // Suppress GENERAL cluster as it's not really a cluster!
+ if (cluster.name.equalsIgnoreCase("GENERAL")) {
+ continue;
+ }
+
+ mdContents += "| " + String.format("%04X", cluster.code);
+ mdContents += " | " + stringToConstant(cluster.name);
+
+ if (cluster.description != null) {
+ mdContents += " | " + cluster.description.get(0).description;
+ } else {
+ mdContents += " |";
+
+ }
+ mdContents += " |\n";
+ }
+
+ return mdContents;
+ }
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclStructureGenerator.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclStructureGenerator.java
new file mode 100644
index 000000000..f9654a9c5
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/ZigBeeZclStructureGenerator.java
@@ -0,0 +1,125 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlCluster;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlField;
+import com.zsmartsystems.zigbee.autocode.xml.ZigBeeXmlStructure;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeZclStructureGenerator extends ZigBeeBaseFieldGenerator {
+
+ ZigBeeZclStructureGenerator(String sourceRootPath, String licenseText, List clusters, String generatedDate,
+ Map dependencies) {
+ super(sourceRootPath, licenseText);
+ this.generatedDate = generatedDate;
+ this.dependencies = dependencies;
+
+ for (ZigBeeXmlCluster cluster : clusters) {
+ try {
+ generateZclClusterStructures(cluster, packageRoot, new File(sourceRootPath));
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void generateZclClusterStructures(ZigBeeXmlCluster cluster, String packageRootPrefix, File sourceRootPath)
+ throws IOException {
+ if (cluster.structures == null) {
+ return;
+ }
+
+ for (final ZigBeeXmlStructure structure : cluster.structures) {
+ final String packageRoot = packageRootPrefix + packageZclProtocolCommand + "."
+ + stringToLowerCamelCase(cluster.name).replace("_", "").toLowerCase();
+ final String packagePath = getPackagePath(sourceRootPath, packageRoot);
+ final File packageFile = getPackageFile(packagePath);
+
+ final String className = structure.className;
+ final PrintWriter out = getClassOut(packageFile, className);
+
+ outputLicense(out);
+
+ importsClear();
+ out.println("package " + packageRoot + ";");
+
+ importsAdd("javax.annotation.Generated");
+ // importsAdd("java.util.HashMap");
+ // importsAdd("java.util.Map");
+
+ importsAdd(packageRootPrefix + ".serialization.ZigBeeSerializable");
+ importsAdd(packageRootPrefix + packageZcl + ".ZclFieldSerializer");
+ importsAdd(packageRootPrefix + packageZcl + ".ZclFieldSerializer");
+ importsAdd(packageRootPrefix + packageZcl + ".ZclFieldDeserializer");
+ importsAdd(packageRootPrefix + packageZclProtocol + ".ZclDataType");
+
+ for (final ZigBeeXmlField field : structure.fields) {
+ // String packageName;
+ // if (getDataTypeClass(field).contains("Descriptor")) {
+ // packageName = packageZdpDescriptors;
+ // } else {
+ // packageName = packageZclField;
+ // }
+ importsAddClass(field);
+ }
+
+ outputImports(out);
+
+ out.println();
+ out.println("/**");
+ out.println(" * " + structure.name + " structure implementation.");
+
+ if (structure.description.size() > 0) {
+ out.println(" * ");
+ outputWithLinebreak(out, "", structure.description);
+ }
+
+ out.println(" *
");
+ out.println(" * Code is auto-generated. Modifications may be overwritten!");
+
+ out.println(" */");
+ outputClassGenerated(out);
+ out.println("public class " + className + " implements ZigBeeSerializable {");
+
+ for (final ZigBeeXmlField field : structure.fields) {
+ out.println(" /**");
+ out.println(" * " + field.name + " structure field.");
+ if (field.description.size() != 0) {
+ out.println(" *
");
+ outputWithLinebreak(out, " ", field.description);
+ }
+ out.println(" */");
+ out.println(" private " + getDataTypeClass(field) + " " + stringToLowerCamelCase(field.name) + ";");
+ out.println();
+ }
+ out.println();
+
+ generateFields(out, "ZigBeeSerializable", className, structure.fields, Collections.emptyList());
+ generateToString(out, className, structure.fields, Collections.emptyList());
+
+ out.println("}");
+
+ out.flush();
+ out.close();
+ }
+ }
+
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlAttribute.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlAttribute.java
new file mode 100644
index 000000000..8c2bc71da
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlAttribute.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode.xml;
+
+import java.math.BigInteger;
+import java.util.List;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeXmlAttribute {
+ public String name;
+ public List description;
+ public Integer code;
+ public Integer arrayStart;
+ public Integer arrayCount;
+ public Integer arrayStep;
+ public String type;
+ public String implementationClass;
+ public String side;
+ public Boolean optional;
+ public Boolean writable;
+ public Boolean reportable;
+ public BigInteger minimumValue;
+ public BigInteger maximumValue;
+ public BigInteger defaultValue;
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlCluster.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlCluster.java
new file mode 100644
index 000000000..2c2c66dc1
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlCluster.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode.xml;
+
+import java.util.List;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeXmlCluster {
+ public String name;
+ public Integer code;
+ public List description;
+ public List commands;
+ public List attributes;
+ public List constants;
+ public List structures;
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlCommand.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlCommand.java
new file mode 100644
index 000000000..938ba6da8
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlCommand.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode.xml;
+
+import java.util.List;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeXmlCommand {
+ public Integer code;
+ public String source;
+ public String name;
+ public List description;
+ public List fields;
+ public ZigBeeXmlResponse response;
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlCondition.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlCondition.java
new file mode 100644
index 000000000..1d5aad78e
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlCondition.java
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode.xml;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeXmlCondition {
+ public String field;
+ public String operator;
+ public String value;
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlConstant.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlConstant.java
new file mode 100644
index 000000000..019285e6a
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlConstant.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode.xml;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeXmlConstant {
+ public String name;
+ public String className;
+ public List description;
+ public Map values;
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/zcl/DataType.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlDescription.java
similarity index 61%
rename from com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/zcl/DataType.java
rename to com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlDescription.java
index 8ba93b7ba..8a0da6567 100644
--- a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/zcl/DataType.java
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlDescription.java
@@ -5,13 +5,14 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.zsmartsystems.zigbee.autocode.zcl;
+package com.zsmartsystems.zigbee.autocode.xml;
/**
- * Created by tlaukkan on 4/10/2016.
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
*/
-public class DataType {
- public String dataTypeName;
- public String dataTypeType;
- public String dataTypeClass;
+public class ZigBeeXmlDescription {
+ public String description;
+ public String format;
}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlField.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlField.java
new file mode 100644
index 000000000..dd4090045
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlField.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode.xml;
+
+import java.util.List;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeXmlField {
+ public String name;
+ public List description;
+ public String type;
+ public String implementationClass;
+ public Boolean array;
+ public String sizer;
+ public ZigBeeXmlCondition condition;
+ public boolean completeOnZero;
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlGlobal.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlGlobal.java
new file mode 100644
index 000000000..9b2f222cb
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlGlobal.java
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode.xml;
+
+import java.util.List;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeXmlGlobal {
+ public List constants;
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlMatcher.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlMatcher.java
new file mode 100644
index 000000000..1824daa68
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlMatcher.java
@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode.xml;
+
+/**
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeXmlMatcher {
+ public String commandField;
+ public String responseField;
+}
diff --git a/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlParser.java b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlParser.java
new file mode 100644
index 000000000..3f4b48841
--- /dev/null
+++ b/com.zsmartsystems.zigbee.autocode/src/main/java/com/zsmartsystems/zigbee/autocode/xml/ZigBeeXmlParser.java
@@ -0,0 +1,370 @@
+/**
+ * Copyright (c) 2016-2019 by the respective copyright holders.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.zsmartsystems.zigbee.autocode.xml;
+
+import java.io.File;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.TreeMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * XML file parser - reads the XML cluster definitions
+ *
+ * @author Chris Jackson (zsmartsystems.com)
+ *
+ */
+public class ZigBeeXmlParser {
+ private final Logger log = LoggerFactory.getLogger(ZigBeeXmlParser.class);
+
+ List files = new ArrayList();
+
+ public ZigBeeXmlParser() {
+ }
+
+ public void addFile(String filename) {
+ files.add(filename);
+ }
+
+ public List parseClusterConfiguration() {
+ List clusters = new ArrayList<>();
+
+ try {
+ for (String file : files) {
+ log.debug("Parsing cluster file: {}", file);
+ // Load the class definitions
+ File fXmlFile = new File(file);
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+ Document doc = dBuilder.parse(fXmlFile);
+ doc.getDocumentElement().normalize();
+
+ // Get all cluster specific definitions
+ NodeList nList = doc.getElementsByTagName("cluster");
+ ZigBeeXmlCluster cluster = (ZigBeeXmlCluster) processNode(nList.item(0));
+ clusters.add(cluster);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+
+ return clusters;
+ }
+
+ public ZigBeeXmlGlobal parseGlobalConfiguration() {
+ ZigBeeXmlGlobal globals = new ZigBeeXmlGlobal();
+ globals.constants = new ArrayList();
+
+ try {
+ for (String file : files) {
+ log.debug("Parsing globals file: {}", file);
+ // Load the class definitions
+ File fXmlFile = new File(file);
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+ Document doc = dBuilder.parse(fXmlFile);
+ doc.getDocumentElement().normalize();
+
+ // Get all global specific definitions
+ NodeList nList = doc.getElementsByTagName("zigbee");
+ ZigBeeXmlGlobal global = (ZigBeeXmlGlobal) processNode(nList.item(0));
+ globals.constants.addAll(global.constants);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+
+ return globals;
+ }
+
+ Object processNode(Node node) {
+ NodeList nodes = node.getChildNodes();
+ Element e;
+
+ switch (node.getNodeName()) {
+ case "zigbee":
+ ZigBeeXmlGlobal global = new ZigBeeXmlGlobal();
+ global.constants = new ArrayList<>();
+ for (int temp = 0; temp < nodes.getLength(); temp++) {
+ if (nodes.item(temp).getNodeName().equals("constant")) {
+ global.constants.add((ZigBeeXmlConstant) processNode(nodes.item(temp)));
+ }
+ }
+ log.info("Done: Global");
+ return global;
+
+ case "cluster":
+ ZigBeeXmlCluster cluster = new ZigBeeXmlCluster();
+
+ e = (Element) node;
+ cluster.code = getInteger(e.getAttribute("code")).intValue();
+
+ cluster.description = new ArrayList();
+ cluster.commands = new ArrayList();
+ cluster.attributes = new ArrayList();
+ cluster.constants = new ArrayList