/******************************************************************************* * Copyright (c) 2015 ARM Ltd. and others * 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 * * Contributors: * ARM Ltd and ARM Germany GmbH - Initial API and implementation *******************************************************************************/ package com.arm.cmsis.pack.rte.devices; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import com.arm.cmsis.pack.DeviceVendor; import com.arm.cmsis.pack.common.CmsisConstants; import com.arm.cmsis.pack.data.CpItem; import com.arm.cmsis.pack.data.CpPackIdComparator; import com.arm.cmsis.pack.data.ICpDeviceItem; import com.arm.cmsis.pack.data.ICpItem; import com.arm.cmsis.pack.data.ICpPack; import com.arm.cmsis.pack.data.ICpPack.PackState; import com.arm.cmsis.pack.enums.EDeviceHierarchyLevel; import com.arm.cmsis.pack.generic.IAttributes; import com.arm.cmsis.pack.item.CmsisMapItem; import com.arm.cmsis.pack.utils.AlnumComparator; /** * Default implementation of IRteDeviceItem */ public class RteDeviceItem extends CmsisMapItem<IRteDeviceItem> implements IRteDeviceItem { protected int fLevel = EDeviceHierarchyLevel.NONE.ordinal(); protected Map<String, ICpDeviceItem> fDevices = null; protected Set<String> fDeviceNames = null; protected boolean fbDeprecated = false; /** * */ public RteDeviceItem() { fLevel = EDeviceHierarchyLevel.ROOT.ordinal(); fName = "All Devices"; //$NON-NLS-1$ } /** * @param parent */ public RteDeviceItem(String name, int level, IRteDeviceItem parent) { super(parent); fLevel = level; fName= name; } @Override protected Map<String, IRteDeviceItem> createMap() { // create TreeMap with Alpha-Numeric case-insensitive ascending sorting return new TreeMap<String, IRteDeviceItem>(new AlnumComparator(false, false)); } /** * Creates device tree from list of Packs * @param packs collection of packs to use * @return device tree as root IRteDeviceItem */ public static IRteDeviceItem createTree(Collection<ICpPack> packs){ IRteDeviceItem root = new RteDeviceItem(); if(packs == null || packs.isEmpty()) { return root; } for(ICpPack pack : packs) { root.addDevices(pack); } return root; } @Override public int getLevel() { return fLevel; } @Override public Collection<ICpDeviceItem> getDevices() { if(fDevices != null) { return fDevices.values(); } return null; } @Override public ICpDeviceItem getDevice() { if(fDevices != null && ! fDevices.isEmpty()) { // Return the latest INSTALLED pack's device ICpDeviceItem firstDevice = null; for (ICpDeviceItem device : fDevices.values()) { if (device.getPack().getPackState() == PackState.INSTALLED) { return device; } if (firstDevice == null) firstDevice = device; } // Otherwise return the latest pack's device return firstDevice; } return null; } @Override public String getProcessorName() { int i = getName().indexOf(':'); if (i >= 0) { return getName().substring(i + 1); } return CmsisConstants.EMPTY_STRING; } @Override public ICpItem getEffectiveProperties() { ICpDeviceItem device = getDevice(); if(device != null){ String processorName = getProcessorName(); return device.getEffectiveProperties(processorName); } return null; } @Override public boolean isDevice() { if(getLevel() < EDeviceHierarchyLevel.DEVICE.ordinal()) { return false; } if(hasChildren()) { return false; } return getDevice() != null; } @Override public boolean isDeprecated() { return fbDeprecated; } @Override public void addDevice(ICpDeviceItem item) { if(item == null) { return; } EDeviceHierarchyLevel eLevel = item.getLevel(); int level = eLevel.ordinal(); if(fLevel == level || fLevel == EDeviceHierarchyLevel.PROCESSOR.ordinal()) { ICpPack pack = item.getPack(); boolean deprecated = pack.isDeprecated(); String packId = pack.getId(); if(fDevices == null) { fDevices = new TreeMap<String, ICpDeviceItem>(new CpPackIdComparator()); } ICpDeviceItem device = fDevices.get(packId); if(device != null) { if(pack == device.getPack()) // not from the same pack return; // installed/downloaded pack has preference if(pack.getPackState().ordinal() > device.getPack().getPackState().ordinal()) { return; } } if(fDevices.isEmpty() || fbDeprecated ) { fbDeprecated = deprecated; } else if(deprecated) { return; } fDevices.put(packId, item); if(fLevel == EDeviceHierarchyLevel.PROCESSOR.ordinal()) { return; } Collection<ICpDeviceItem> subItems = item.getDeviceItems(); if(subItems != null && !subItems.isEmpty()) { for(ICpDeviceItem i : subItems ){ addDevice(i); } } else if(level >= EDeviceHierarchyLevel.DEVICE.ordinal()) { addDeviceName(getName()); if( item.getProcessorCount() > 1) { // add processor leaves Map<String, ICpItem> processors = item.getProcessors(); for(Entry<String, ICpItem> e : processors.entrySet()) { String fullName = item.getName() + ":" + e.getKey(); //$NON-NLS-1$ addDeviceItem(item, fullName, EDeviceHierarchyLevel.PROCESSOR.ordinal()); } } } return; } else if(fLevel == EDeviceHierarchyLevel.ROOT.ordinal()) { String vendorName = DeviceVendor.getOfficialVendorName(item.getVendor()); addDeviceItem(item, vendorName, EDeviceHierarchyLevel.VENDOR.ordinal()); return; } else if(fLevel > level) {// should not happen if algorithm is correct return; } // other cases addDeviceItem(item, item.getName(), level); } protected void addDeviceItem(ICpDeviceItem item, final String itemName, final int level) { String fullName = itemName; if(level >= EDeviceHierarchyLevel.DEVICE.ordinal()){ Map<String, ICpItem> processors = item.getProcessors(); if(processors.size() == 1) { Entry<String, ICpItem> e = processors.entrySet().iterator().next(); String procName = e.getKey(); if(procName != null && ! procName.isEmpty()) { fullName += ':' + procName; } } } IRteDeviceItem di = getChild(fullName); if(di == null ) { di = new RteDeviceItem(fullName, level, this); addChild(di); } di.addDevice(item); } @Override public void addDevices(ICpPack pack) { if(pack == null) { return; } Collection<? extends ICpItem> devices = pack.getGrandChildren(CmsisConstants.DEVICES_TAG); if(devices == null) { return; } for(ICpItem item : devices) { if(!(item instanceof ICpDeviceItem)) { continue; } ICpDeviceItem deviceItem = (ICpDeviceItem)item; addDevice(deviceItem); } } @Override public void removeDevice(ICpDeviceItem item) { if (item == null) { return; } EDeviceHierarchyLevel eLevel = item.getLevel(); int level = eLevel.ordinal(); if(fLevel == level || fLevel == EDeviceHierarchyLevel.PROCESSOR.ordinal()) { ICpPack pack = item.getPack(); String packId = pack.getId(); if(fDevices == null) { return; } fDevices.remove(packId); if(fLevel == EDeviceHierarchyLevel.PROCESSOR.ordinal()) { getParent().removeChild(this); return; } Collection<ICpDeviceItem> subItems = item.getDeviceItems(); if(subItems != null && !subItems.isEmpty()) { for(ICpDeviceItem subItem : subItems ){ removeDevice(subItem); } } else if(level >= EDeviceHierarchyLevel.DEVICE.ordinal() && item.getProcessorCount() > 1) { // add processor leaves Map<String, ICpItem> processors = item.getProcessors(); for(Entry<String, ICpItem> e : processors.entrySet()) { String procName = item.getName() + ":" + e.getKey(); //$NON-NLS-1$ removeDeviceItem(item, procName, EDeviceHierarchyLevel.PROCESSOR.ordinal()); } } if (fDevices.size() == 0) { removeDeviceName(fName); getParent().removeChild(this); } return; } else if(fLevel == EDeviceHierarchyLevel.ROOT.ordinal()) { IRteDeviceItem d = findItem(item.getName(), item.getVendor(), false); if (d != null) { d.removeDevice(item); IRteDeviceItem p = d.getParent(); while (p != null && p.getLevel() > EDeviceHierarchyLevel.ROOT.ordinal()) { if (p.getChildren() == null || p.getChildren().isEmpty()) { IRteDeviceItem pp = p.getParent(); pp.removeChild(p); p = pp; } else { break; } } } return; } else if(fLevel > level) {// should not happen if algorithm is correct return; } removeDeviceItem(item, item.getName(), level); } protected void removeDeviceItem(ICpDeviceItem item, String itemName, int level) { IRteDeviceItem di = getChild(itemName); if (di != null) { di.removeDevice(item); } } @Override public void removeDevices(ICpPack pack) { if(pack == null) { return; } Collection<? extends ICpItem> devices = pack.getGrandChildren(CmsisConstants.DEVICES_TAG); if(devices != null) { for(ICpItem item : devices) { if(!(item instanceof ICpDeviceItem)) { continue; } ICpDeviceItem deviceItem = (ICpDeviceItem)item; removeDevice(deviceItem); } } } @Override public IRteDeviceItem findItem(final String deviceName, final String vendor, final boolean onlyDevice) { if(fLevel == EDeviceHierarchyLevel.ROOT.ordinal() && vendor != null && !vendor.isEmpty()) { String vendorName = DeviceVendor.getOfficialVendorName(vendor); IRteDeviceItem dti = getChild(vendorName); if(dti != null) { return dti.findItem(deviceName, vendorName, onlyDevice); } } else { // check if device item can be found directly on this level IRteDeviceItem dti = getChild(deviceName); if(dti != null) { if (!onlyDevice) { if (deviceName.contains("*")) { //$NON-NLS-1$ // TODO: find a better criterion in this case return dti.getParent(); } return dti; } else if (dti.getLevel() > EDeviceHierarchyLevel.SUBFAMILY.ordinal()) { return dti; } } // search in children Collection<? extends IRteDeviceItem> children = getChildren(); if(children == null) { return null; } for(IRteDeviceItem child : children){ dti = child.findItem(deviceName, vendor, onlyDevice); if(dti != null) { if (!onlyDevice) { return dti; } else if (dti.getLevel() > EDeviceHierarchyLevel.SUBFAMILY.ordinal()) { return dti; } } } } return null; } @Override public IRteDeviceItem findItem(final IAttributes attributes) { String deviceName = CpItem.getDeviceName(attributes); if(deviceName == null || deviceName.isEmpty()) { return null; } String vendor = attributes.getAttribute(CmsisConstants.DVENDOR); return findItem(deviceName, vendor, true); } @Override public IRteDeviceItem getVendorItem() { if(getLevel() == EDeviceHierarchyLevel.VENDOR.ordinal()) { return this; } else if(getLevel() > EDeviceHierarchyLevel.VENDOR.ordinal()) { if(getParent() != null) { return getParent().getVendorItem(); } } return null; } @Override public IRteDeviceItem getVendorItem(String vendor) { vendor = DeviceVendor.getOfficialVendorName(vendor); if(getLevel() == EDeviceHierarchyLevel.ROOT.ordinal()) { return getChild(vendor); } IRteDeviceItem root = getRoot(); if(root != null) { return root.getVendorItem(vendor); } return null; } @Override public String getDescription() { ICpDeviceItem deviceItem = getDevice(); if(deviceItem != null) { String description = deviceItem.getDescription(); if(description != null && !description.isEmpty()) { return description; } } if(getParent() != null) { return getParent().getDescription(); } return CmsisConstants.EMPTY_STRING; } @Override public String getUrl() { ICpDeviceItem device = getDevice(); if(device != null) { return device.getUrl(); } return null; } @Override public String getDoc() { ICpDeviceItem device = getDevice(); if(device != null) { return device.getDoc(); // TODO: return a collection of documents } return null; } @Override public Set<String> getAllDeviceNames() { if(fDeviceNames == null ){ fDeviceNames = new HashSet<String>(); if(isDevice()) addDeviceName(getDevice().getName()); if (fChildMap != null) { for (IRteDeviceItem item : fChildMap.values()) { fDeviceNames.addAll(item.getAllDeviceNames()); } } } return fDeviceNames; } @Override public String getVendorName() { if (fLevel == EDeviceHierarchyLevel.VENDOR.ordinal()) { return fName; } if (getParent() != null) { return getParent().getVendorName(); } return CmsisConstants.EMPTY_STRING; } @Override public void addDeviceName(String name) { if (fDeviceNames != null ) fDeviceNames.add(name); if (getParent() != null) { getParent().addDeviceName(name); } } @Override public void removeDeviceName(String name) { if (fDeviceNames != null) fDeviceNames.remove(name); if (getParent() != null) { getParent().removeDeviceName(name); } } }