gt:             msgOffset += varSize;
context: /**
   * Copyright (c) 2016-2017 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.zwave.commandclass.impl;
  
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.util.HashMap;
  import java.util.Map;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * Class to implement the Z-Wave command class <b>COMMAND_CLASS_METER</b> version <b>4</b>.
   * <p>
   * Command Class Meter
   * <p>
   * This class provides static methods for processing received messages (message handler) and
   * methods to get a message to send on the Z-Wave network.
   * <p>
   * Command class key is 0x32.
   * <p>
   * Note that this code is autogenerated. Manual changes may be overwritten.
   *
   * @author Chris Jackson - Initial contribution of Java code generator
   */
  public class CommandClassMeterV4 {
      private static final Logger logger = LoggerFactory.getLogger(CommandClassMeterV4.class);
  
      /**
       * Integer command class key for COMMAND_CLASS_METER
       */
      public final static int COMMAND_CLASS_KEY = 0x32;
  
      /**
       * Meter Get Command Constant
       */
      public final static int METER_GET = 0x01;
      /**
       * Meter Report Command Constant
       */
      public final static int METER_REPORT = 0x02;
      /**
       * Meter Supported Get Command Constant
       */
      public final static int METER_SUPPORTED_GET = 0x03;
      /**
       * Meter Supported Report Command Constant
       */
      public final static int METER_SUPPORTED_REPORT = 0x04;
      /**
       * Meter Reset Command Constant
       */
      public final static int METER_RESET = 0x05;
  
      /**
       * Map holding constants for MeterSupportedReportProperties1
       */
      private static Map<Integer, String> constantMeterSupportedReportProperties1 = new HashMap<Integer, String>();
  
      /**
       * Map holding constants for MeterSupportedReportRateType
       */
      private static Map<Integer, String> constantMeterSupportedReportRateType = new HashMap<Integer, String>();
  
      /**
       * Map holding constants for MeterSupportedReportProperties2
       */
      private static Map<Integer, String> constantMeterSupportedReportProperties2 = new HashMap<Integer, String>();
  
      /**
       * Map holding constants for MeterGetRateType
       */
      private static Map<Integer, String> constantMeterGetRateType = new HashMap<Integer, String>();
  
      /**
       * Map holding constants for MeterReportRateType
       */
      private static Map<Integer, String> constantMeterReportRateType = new HashMap<Integer, String>();
  
      /**
       * Map holding constants for MeterSupportedReportMeterType
       */
      private static Map<Integer, String> constantMeterSupportedReportMeterType = new HashMap<Integer, String>();
  
      /**
       * Map holding constants for MeterReportProperties1
       */
      private static Map<Integer, String> constantMeterReportProperties1 = new HashMap<Integer, String>();
  
      /**
       * Map holding constants for MeterReportMeterType
       */
      private static Map<Integer, String> constantMeterReportMeterType = new HashMap<Integer, String>();
  
      static {
          // Constants for MeterSupportedReportProperties1
          constantMeterSupportedReportProperties1.put(0x80, "METER_RESET");
  
          // Constants for MeterSupportedReportRateType
          constantMeterSupportedReportRateType.put(0x00, "IMPORT_ONLY");
          constantMeterSupportedReportRateType.put(0x01, "EXPORT_ONLY");
          constantMeterSupportedReportRateType.put(0x02, "IMPORT_AND_EXPORT");
  
          // Constants for MeterSupportedReportProperties2
          constantMeterSupportedReportProperties2.put(0x80, "M_S_T");
  
          // Constants for MeterGetRateType
          constantMeterGetRateType.put(0x00, "IMPORT");
          constantMeterGetRateType.put(0x01, "EXPORT");
          constantMeterGetRateType.put(0x02, "NOT_TO_BE_USED");
  
          // Constants for MeterReportRateType
          constantMeterReportRateType.put(0x00, "IMPORT");
          constantMeterReportRateType.put(0x01, "EXPORT");
          constantMeterReportRateType.put(0x02, "NOT_TO_BE_USED");
  
          // Constants for MeterSupportedReportMeterType
          constantMeterSupportedReportMeterType.put(0x00, "ELECTRIC_METER");
          constantMeterSupportedReportMeterType.put(0x01, "GAS_METER");
          constantMeterSupportedReportMeterType.put(0x02, "WATER_METER");
  
          // Constants for MeterReportProperties1
          constantMeterReportProperties1.put(0x80, "SCALE_BIT_2");
  
          // Constants for MeterReportMeterType
          constantMeterReportMeterType.put(0x00, "ELECTRIC_METER");
          constantMeterReportMeterType.put(0x01, "GAS_METER");
          constantMeterReportMeterType.put(0x02, "WATER_METER");
      }
  
      /**
       * Creates a new message with the METER_GET command.
       * <p>
       * Meter Get
       *
       * @param scale {@link Integer}
       * @param rateType {@link String}
       *            Can be one of the following -:
       *            <p>
       *            <ul>
       *            <li>IMPORT
       *            <li>EXPORT
       *            <li>NOT_TO_BE_USED
       *            </ul>
       * @param scale2 {@link Integer}
       * @return the {@link byte[]} array with the command to send
       */
      static public byte[] getMeterGet(Integer scale, String rateType, Integer scale2) {
          logger.debug("Creating command message METER_GET version 4");
  
          ByteArrayOutputStream outputData = new ByteArrayOutputStream();
          outputData.write(COMMAND_CLASS_KEY);
          outputData.write(METER_GET);
  
          // Process 'Properties1'
          int valProperties1 = 0;
          valProperties1 |= ((scale << 3) & 0x38);
          int varRateType = Integer.MAX_VALUE;
          for (Integer entry : constantMeterGetRateType.keySet()) {
              if (constantMeterGetRateType.get(entry).equals(rateType)) {
                  varRateType = entry;
                  break;
              }
          }
          if (varRateType == Integer.MAX_VALUE) {
              throw new IllegalArgumentException("Unknown constant value '" + rateType + "' for rateType");
          }
          valProperties1 |= varRateType << 6 & 0xC0;
          outputData.write(valProperties1);
  
          // Process 'Scale 2'
          outputData.write(scale2);
  
          return outputData.toByteArray();
      }
  
      /**
       * Processes a received frame with the METER_GET command.
       * <p>
       * Meter Get
       * <p>
       * The output data {@link Map} has the following properties -:
       *
       * <ul>
       * <li>SCALE {@link Integer}
       * <li>RATE_TYPE {@link String}
       * Can be one of the following -:
       * <p>
       * <ul>
       * <li>IMPORT
       * <li>EXPORT
       * <li>NOT_TO_BE_USED
       * </ul>
       * <li>SCALE_2 {@link Integer}
       * </ul>
       *
       * @param payload the {@link byte[]} payload data to process
       * @return a {@link Map} of processed response data
       */
      public static Map<String, Object> handleMeterGet(byte[] payload) {
          // Create our response map
          Map<String, Object> response = new HashMap<String, Object>();
  
          // Process 'Properties1'
          response.put("SCALE", Integer.valueOf(payload[2] & 0x38 >> 3));
          response.put("RATE_TYPE", constantMeterGetRateType.get((payload[2] & 0xC0) >> 6));
  
          // Process 'Scale 2'
          response.put("SCALE_2", Integer.valueOf(payload[3]));
  
          // Return the map of processed response data;
          return response;
      }
  
      /**
       * Creates a new message with the METER_REPORT command.
       * <p>
       * Meter Report
       *
       * @param meterType {@link String}
       *            Can be one of the following -:
       *            <p>
       *            <ul>
       *            <li>ELECTRIC_METER
       *            <li>GAS_METER
       *            <li>WATER_METER
       *            </ul>
       * @param rateType {@link String}
       *            Can be one of the following -:
       *            <p>
       *            <ul>
       *            <li>IMPORT
       *            <li>EXPORT
       *            <li>NOT_TO_BE_USED
       *            </ul>
       * @param scaleBit2 {@link Boolean}
       * @param scaleBits10 {@link Integer}
       * @param precision {@link Integer}
       * @param meterValue {@link byte[]}
       * @param deltaTime {@link Integer}
       * @param previousMeterValue {@link byte[]}
       * @param scale2 {@link Integer}
       * @return the {@link byte[]} array with the command to send
       */
      static public byte[] getMeterReport(String meterType, String rateType, Boolean scaleBit2, Integer scaleBits10,
              Integer precision, byte[] meterValue, Integer deltaTime, byte[] previousMeterValue, Integer scale2) {
          logger.debug("Creating command message METER_REPORT version 4");
  
          ByteArrayOutputStream outputData = new ByteArrayOutputStream();
          outputData.write(COMMAND_CLASS_KEY);
          outputData.write(METER_REPORT);
  
          // Process 'Properties1'
          int valProperties1 = 0;
          int varMeterType = Integer.MAX_VALUE;
          for (Integer entry : constantMeterReportMeterType.keySet()) {
              if (constantMeterReportMeterType.get(entry).equals(meterType)) {
                  varMeterType = entry;
                  break;
              }
          }
          if (varMeterType == Integer.MAX_VALUE) {
              throw new IllegalArgumentException("Unknown constant value '" + meterType + "' for meterType");
          }
          valProperties1 |= varMeterType & 0x1F;
          int varRateType = Integer.MAX_VALUE;
          for (Integer entry : constantMeterReportRateType.keySet()) {
              if (constantMeterReportRateType.get(entry).equals(rateType)) {
                  varRateType = entry;
                  break;
              }
          }
          if (varRateType == Integer.MAX_VALUE) {
              throw new IllegalArgumentException("Unknown constant value '" + rateType + "' for rateType");
          }
          valProperties1 |= varRateType << 5 & 0x60;
          valProperties1 |= scaleBit2 ? 0x80 : 0;
          outputData.write(valProperties1);
  
          // Process 'Properties2'
          // Size is used by 'Meter Value' and 'Previous Meter Value'
          int size = meterValue.length;
          int valProperties2 = 0;
          valProperties2 |= size & 0x07;
          valProperties2 |= ((scaleBits10 << 3) & 0x18);
          valProperties2 |= ((precision << 5) & 0xE0);
          outputData.write(valProperties2);
  
          // Process 'Meter Value'
          if (meterValue != null) {
              try {
                  outputData.write(meterValue);
              } catch (IOException e) {
              }
          }
  
          // Process 'Delta Time'
          outputData.write((deltaTime >> 8) & 0xff);
          outputData.write(deltaTime & 0xff);
  
          // Process 'Previous Meter Value'
          if (previousMeterValue != null) {
              try {
                  outputData.write(previousMeterValue);
              } catch (IOException e) {
              }
          }
  
          // Process 'Scale 2'
          outputData.write(scale2);
  
          return outputData.toByteArray();
      }
  
      /**
       * Processes a received frame with the METER_REPORT command.
       * <p>
       * Meter Report
       * <p>
       * The output data {@link Map} has the following properties -:
       *
       * <ul>
       * <li>METER_TYPE {@link String}
       * Can be one of the following -:
       * <p>
       * <ul>
       * <li>ELECTRIC_METER
       * <li>GAS_METER
       * <li>WATER_METER
       * </ul>
       * <li>RATE_TYPE {@link String}
       * Can be one of the following -:
       * <p>
       * <ul>
       * <li>IMPORT
       * <li>EXPORT
       * <li>NOT_TO_BE_USED
       * </ul>
       * <li>SCALE_BIT_2 {@link Boolean}
       * <li>SCALE_BITS_10 {@link Integer}
       * <li>PRECISION {@link Integer}
       * <li>METER_VALUE {@link byte[]}
       * <li>DELTA_TIME {@link Integer}
       * <li>PREVIOUS_METER_VALUE {@link byte[]}
       * <li>SCALE_2 {@link Integer}
       * </ul>
       *
       * @param payload the {@link byte[]} payload data to process
       * @return a {@link Map} of processed response data
       */
      public static Map<String, Object> handleMeterReport(byte[] payload) {
          // Create our response map
          Map<String, Object> response = new HashMap<String, Object>();
  
          // We're using variable length fields, so track the offset
          int msgOffset = 2;
  
          // Process 'Properties1'
          response.put("METER_TYPE", constantMeterReportMeterType.get(payload[msgOffset] & 0x1F));
          response.put("RATE_TYPE", constantMeterReportRateType.get((payload[msgOffset] & 0x60) >> 5));
          response.put("SCALE_BIT_2", Boolean.valueOf((payload[msgOffset] & 0x80) != 0));
          msgOffset += 1;
  
          // Process 'Properties2'
          // Size is used by 'Meter Value' and 'Previous Meter Value'
          int varSize = payload[msgOffset] & 0x07;
          response.put("SCALE_BITS_10", Integer.valueOf(payload[msgOffset] & 0x18 >> 3));
          response.put("PRECISION", Integer.valueOf(payload[msgOffset] & 0xE0 >> 5));
          msgOffset += 1;
  
          // Process 'Meter Value'
          ByteArrayOutputStream valMeterValue = new ByteArrayOutputStream();
          for (int cntMeterValue = 0; cntMeterValue < varSize; cntMeterValue++) {
              valMeterValue.write(payload[msgOffset + cntMeterValue]);
          }
          response.put("METER_VALUE", valMeterValue.toByteArray());
          msgOffset += varSize;
  
          // Process 'Delta Time'
          response.put("DELTA_TIME", Integer.valueOf(((payload[msgOffset] & 0xff) << 8) + (payload[msgOffset + 1] & 0xff)));
          msgOffset += 2;
  
          // Process 'Previous Meter Value' (optional)
          if (true) {
              ByteArrayOutputStream valPreviousMeterValue = new ByteArrayOutputStream();
              for (int cntPreviousMeterValue = 0; cntPreviousMeterValue < varSize; cntPreviousMeterValue++) {
                  valPreviousMeterValue.write(payload[msgOffset + cntPreviousMeterValue]);
              }
              response.put("PREVIOUS_METER_VALUE", valPreviousMeterValue.toByteArray());
  