/** * Copyright (c) 2010-2016 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 org.openhab.binding.plclogo.internal; import java.util.HashMap; import org.openhab.model.item.binding.BindingConfigParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Memory configruration for PLCLogo item binding * One memory configuration may be assigned for input and another for output for same item. * * @author Vladimir Grebenschikov * @author Alexander Falkenstern * @since 1.9.0 */ public class PLCLogoMemoryConfig { private String block = null; // Logo-style block name like Q10 private PLCLogoBlock.Kind kind = null; // normalized memory type VB|VW|I|Q|M|AO|AQ|AM private int address = -1; // address in logo memory block private int bit = -1; // informational bit (-1 if not used) private int index = -1; // normalized index of element (starting from 0) private static final Logger logger = LoggerFactory.getLogger(PLCLogoBinding.class); // @formatter:off private static final PLCLogoBlock PLCLogoBlock0BA7[] = { new PLCLogoBlock(PLCLogoBlock.Kind.VB, 0), new PLCLogoBlock(PLCLogoBlock.Kind.VW, 0), new PLCLogoBlock(PLCLogoBlock.Kind.I, 923), // I starts at 923 for 3 bytes new PLCLogoBlock(PLCLogoBlock.Kind.Q, 942), // Q starts at 942 for 2 bytes new PLCLogoBlock(PLCLogoBlock.Kind.M, 948), // M starts at 948 for 2 bytes new PLCLogoBlock(PLCLogoBlock.Kind.AI, 926), // AI starts at 926 for 8 words new PLCLogoBlock(PLCLogoBlock.Kind.AQ, 944), // AQ starts at 944 for 2 words new PLCLogoBlock(PLCLogoBlock.Kind.AM, 952) // AM starts at 952 for 16 words }; private static final PLCLogoBlock PLCLogoBlock0BA8[] = { new PLCLogoBlock(PLCLogoBlock.Kind.VB, 0), new PLCLogoBlock(PLCLogoBlock.Kind.VW, 0), new PLCLogoBlock(PLCLogoBlock.Kind.I, 1024), // I starts at 1024 for 8 bytes new PLCLogoBlock(PLCLogoBlock.Kind.Q, 1064), // Q starts at 1064 for 8 bytes new PLCLogoBlock(PLCLogoBlock.Kind.M, 1104), // M starts at 1104 for 14 bytes new PLCLogoBlock(PLCLogoBlock.Kind.AI, 1032), // AI starts at 1032 for 32 bytes -> 16 words new PLCLogoBlock(PLCLogoBlock.Kind.AQ, 1072), // AQ starts at 1072 for 32 bytes -> 16 words new PLCLogoBlock(PLCLogoBlock.Kind.AM, 1118), // Analog markers starts at 1118 for 128 bytes(64 words) new PLCLogoBlock(PLCLogoBlock.Kind.NI, 1246), // Network inputs starts at 1246 for 16 bytes new PLCLogoBlock(PLCLogoBlock.Kind.NAI, 1262), // Network analog inputs starts at 1262 for 128 bytes(64 words) new PLCLogoBlock(PLCLogoBlock.Kind.NQ, 1390), // Network outputs starts at 1390 for 16 bytes new PLCLogoBlock(PLCLogoBlock.Kind.NAQ, 1406) // Network analog inputs starts at 1406 for 64 bytes(32 words) }; // @formatter:on final static HashMap<PLCLogoBlock.Kind, PLCLogoBlock> PLCLogoBlock0BA7Map = makeBlocksMap(PLCLogoBlock0BA7); final static HashMap<PLCLogoBlock.Kind, PLCLogoBlock> PLCLogoBlock0BA8Map = makeBlocksMap(PLCLogoBlock0BA8); private static HashMap<PLCLogoBlock.Kind, PLCLogoBlock> makeBlocksMap(PLCLogoBlock blocks[]) { HashMap<PLCLogoBlock.Kind, PLCLogoBlock> bmap = new HashMap<PLCLogoBlock.Kind, PLCLogoBlock>(); for (PLCLogoBlock b : blocks) { bmap.put(b.getKind(), b); } return bmap; } public PLCLogoMemoryConfig(String memory) throws BindingConfigParseException { String[] memparts = memory.split("\\."); block = memparts[0]; if (block.length() < 2) { logger.error("Wrong block definition for {}", block); throw new BindingConfigParseException("Wrong block definition for " + block); } if (Character.isDigit(block.charAt(1))) { kind = PLCLogoBlock.Kind.valueOf(block.substring(0, 1).toUpperCase()); index = Integer.parseInt(block.substring(1)); } else if (Character.isDigit(block.charAt(2))) { kind = PLCLogoBlock.Kind.valueOf(block.substring(0, 2).toUpperCase()); index = Integer.parseInt(block.substring(2)); } else if (Character.isDigit(block.charAt(3))) { kind = PLCLogoBlock.Kind.valueOf(block.substring(0, 3).toUpperCase()); index = Integer.parseInt(block.substring(3)); } else { logger.error("Wrong block type detected: {}", block); throw new BindingConfigParseException("Wrong block type detected: " + block); } if (memparts.length > 1) { logger.debug("Memory map parts {} : {}", memparts[0], memparts[1]); bit = Integer.parseInt(memparts[1]); if ((bit < 0) || (bit > 7)) { logger.error("Invalid bit {} for block {} found", bit, block); throw new BindingConfigParseException("Invalid bit " + bit + " for block " + block + " found"); } } } public String getBlockName() { return this.block; } public PLCLogoBlock.Kind getKind() { return this.kind; } public PLCLogoBlock getBlock(PLCLogoModel model) throws BindingConfigParseException { if (model == PLCLogoModel.LOGO_MODEL_0BA7) { return PLCLogoBlock0BA7Map.get(kind); } else if (model == PLCLogoModel.LOGO_MODEL_0BA8) { return PLCLogoBlock0BA8Map.get(kind); } else { throw new BindingConfigParseException("Wrong model " + model); } } public int getAddress(PLCLogoModel model) throws BindingConfigParseException { // First time this function called, address is less 0 -> Calculate it if (address < 0) { address = getBlock(model).getAddress(index); logger.debug("Address of {} = {}", block, address + ((bit != -1) ? ("." + bit) : "")); } return address; } public int getBit(PLCLogoModel model) throws BindingConfigParseException { // First time this function called, bit is less 0 excepting VB/VW blocks -> Calculate it if ((bit < 0) && PLCLogoBlock.isBitwise(kind)) { bit = getBlock(model).getBit(index); if ((bit < 0) || (bit > 7)) { logger.error("Invalid bit {} for block {} found", bit, block); throw new BindingConfigParseException("Invalid bit " + bit + " for block " + block + " found"); } logger.debug("Address of {} = {}.{}", block, address, bit); } return bit; } public boolean isInRange(PLCLogoModel model) { if (model == PLCLogoModel.LOGO_MODEL_0BA7) { return (address >= 0) && (address < 984); } else if (model == PLCLogoModel.LOGO_MODEL_0BA8) { return (address >= 0) && (address <= 1469); } else { return false; } } public boolean isDigital() { return PLCLogoBlock.isBitwise(kind) || (PLCLogoBlock.isGeneral(kind) && (bit >= 0)); } public boolean isInput() { return PLCLogoBlock.isInput(kind) || PLCLogoBlock.isGeneral(kind); } public boolean isOutput() { return !PLCLogoBlock.isInput(kind) || PLCLogoBlock.isGeneral(kind); } }