/**
   * 升级第4步 检查升级包是否传输完毕,首先客户端读取image_transferred_blocks_status(image
   * transfer对象的属性3)获取各个imageBlock是否已接收的bitmap,如发现有遗漏的block,则补发相应的block,直至所有的block都被表计接收;当(image_transferred_blocks/8)>
   * ImageBlockSize时,客户端需采用选择性读(选择性参数=entry_descriptor)来实现分组读取所有image_transferred_blocks的bitmap,如ImageBlockSize=100,image_transferred_blocks=1800,则客户端需要分三次来读取bitmap(第一次的entry_descriptor中From_entry=0,to_entry=99;第二次entry_descriptor中From_entry=100,to_entry=199;第三次entry_descriptor中From_entry=200,to_entry=00。Entry_descriptor的使用详见《DLMS/COSEM应用层标准》);
   *
   * @param req
   * @param dr
   */
  private void upgradeStep_04(DlmsRequest req, DlmsRequest dr) {
    setRequestParam(dr, new ObisDescription(18, "0.0.44.0.0.255", 3));
    dr.setOpType(DLMS_OP_TYPE.OP_GET);
    dr.removeAppendParam(DlmsUpgradeAssisant.CURRENT_RESSIUE_NUM);
    int i_maxSize = (Integer) dr.getAppendParam(DlmsUpgradeAssisant.MAX_SIZE);
    int blockCount = (Integer) dr.getAppendParam(DlmsUpgradeAssisant.BLOCK_COUNT);

    if (blockCount / 8
        > i_maxSize) { // 按照新的标准:如果(image_transferred_blocks/8)> ImageBlockSize,选择性读,否则,直接读

      int fromIndex = getRessiueBlocks(req, dr);

      int nextIndex = fromIndex + i_maxSize - 1; // 假如读3次的话[0,i_maxSize-1],[i_maxSize,199]
      if (nextIndex > (blockCount / 8)) { // 最后一次读,读完之后,转移到第4步
        nextIndex = 0;
        dr.setOperator(DlmsUpgradeAssisant.UPGRADE_04);
      } else { // 继续读
        dr.setOperator(DlmsUpgradeAssisant.UPGRADE_READMAP);
        dr.addAppendParam(DlmsUpgradeAssisant.CURRENT_INDEX, nextIndex + 1);
      }
      // 分多次读
      SelectiveAccessDescriptor sad = new SelectiveAccessDescriptor();
      sad.selectByIndex(fromIndex, nextIndex);
      dr.getParams()[0].accessSelector = 2;
      dr.getParams()[0].data.assignValue(sad.getParameter());
    } else { // 直接读,读完之后转移到第4步
      dr.setOperator(DlmsUpgradeAssisant.UPGRADE_04);
    }
  }
  /**
   * 升级初始化
   *
   * @param req
   * @param dr
   * @param i_maxSize
   */
  private void upgradeInit(DlmsRequest req, DlmsRequest dr, int i_maxSize) {
    dr.removeAppendParam(DlmsUpgradeAssisant.CURRENT_BLOCK_NUM);
    dr.addAppendParam(DlmsUpgradeAssisant.MAX_SIZE, i_maxSize);
    dr.setOpType(DLMS_OP_TYPE.OP_ACTION);
    setRequestParam(dr, new ObisDescription(18, "0.0.44.0.0.255", 1)); // 初始化
    DlmsData data = new DlmsData();
    DlmsData[] datas = new DlmsData[2];
    byte[] content = DlmsUpgradeAssisant.getInstance().getFtpFileContent(req);
    dr.addAppendParam(DlmsUpgradeAssisant.UPGRADE_CONTENT, content);
    dr.addAppendParam(DlmsUpgradeAssisant.BLOCK_COUNT, content.length / i_maxSize); // 块数

    byte[] fileHead = fileHeadConstruct(req);
    dr.addAppendParam(DlmsUpgradeAssisant.FILE_HEAD, HexDump.toHex(fileHead));
    datas[0] = new DlmsData(); // image_identifier
    datas[0].setOctetString(fileHead);
    datas[1] = new DlmsData(); // image_szie
    datas[1].setDoubleLongUnsigned(content.length);
    ASN1SequenceOf struct = new ASN1SequenceOf(datas);
    data.setStructure(struct);
    dr.getParams()[0].data = data;
    dr.setOperator(DlmsUpgradeAssisant.UPGRADE_02);
  }