/*******************************************************************************
* 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.data;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.arm.cmsis.pack.DeviceVendor;
import com.arm.cmsis.pack.common.CmsisConstants;
import com.arm.cmsis.pack.enums.EDeviceHierarchyLevel;
/**
* Default implementation of ICpDeviceItem interface
*/
public class CpDeviceItem extends CpDeviceItemContainer implements ICpDeviceItem {
protected EDeviceHierarchyLevel level = null;
protected List<ICpDeviceItem> deviceItems = null;
protected Map<String, ICpItem> processors = null; // effective processors
protected Map<String, ICpItem > effectiveProperties = null;
protected Map<String, ICpDebugConfiguration > debugConfigurations = null;
/**
* @param parent
* @param tag
*/
public CpDeviceItem(ICpItem parent, String tag) {
super(parent, tag);
}
@Override
public ICpDeviceItem getDeviceItemParent() {
ICpItem parent = getParent();
if (parent != null && parent instanceof ICpDeviceItem) {
return (ICpDeviceItem) parent;
}
return null;
}
@Override
public boolean hasDeviceItems() {
return deviceItems != null && !deviceItems.isEmpty();
}
@Override
public List<ICpDeviceItem> getDeviceItems() {
return deviceItems;
}
@Override
public void addChild(ICpItem item) {
cachedChildArray = null; // invalidate
if(item instanceof ICpDeviceItem) {
if(deviceItems == null) {
deviceItems = new LinkedList<ICpDeviceItem>();
}
deviceItems.add((ICpDeviceItem) item);
} else { // property
List<ICpItem> children = children();
String pname = item.getProcessorName();
if(pname != null && !pname.isEmpty()) {
children.add(0, item); // add properties with Pname attribute always to front ( makes collecting effective properties easier)
} else {
children.add(item);
}
}
}
@Override
public EDeviceHierarchyLevel getLevel() {
if (level == null) {
level = EDeviceHierarchyLevel.fromString(getTag());
}
return level;
}
@Override
public ICpItem getEffectiveParent() {
ICpItem parent = getParent();
if(parent != null && parent instanceof ICpDeviceItem) {
return parent;
}
return null;
}
@Override
public int getProcessorCount() {
return getProcessors().size();
}
@Override
public synchronized ICpItem getProcessor(String processorName) {
getProcessors(); // ensure processors map
return processors.get(processorName);
}
@Override
public synchronized Map<String, ICpItem> getProcessors() {
if(processors == null) {
processors = new HashMap<String, ICpItem>();
for(ICpDeviceItem deviceItem = this; deviceItem != null; deviceItem = deviceItem.getDeviceItemParent()){
Collection<? extends ICpItem> children = deviceItem.getChildren();
if(children == null) {
continue;
}
for(ICpItem item : children) {
if(item.getTag().equals(CmsisConstants.PROCESSOR_TAG)) {
ICpDeviceProperty p = (ICpDeviceProperty)item;
String pname = p.getProcessorName();
ICpItem inserted = processors.get(pname);
if(inserted == null) {
processors.put(pname, p);
} else {
// add missing attributes, but do not replace existing ones (we go down-up)
inserted.mergeEffectiveContent(p, pname);
}
}
}
}
}
return processors;
}
@Override
public synchronized ICpItem getEffectiveProperties(String processorName) {
if(effectiveProperties == null) {
// ensure filled processor collection
getProcessors();
// collect properties for all processors
effectiveProperties = new HashMap<String, ICpItem >();
}
if(processorName != null && processorName.isEmpty() && !processors.containsKey(processorName)) {
return null;
}
ICpItem props = effectiveProperties.get(processorName);
if(props != null) {
return props;
}
props = new CpItem(this);
effectiveProperties.put(processorName, props);
// add processor attributes to the properties
ICpItem pItem = getProcessor(processorName);
if(pItem != null) {
props.attributes().setAttributes(pItem.attributes().getAttributesAsMap());
// directly insert processor property since it is already collected
props.addChild(pItem);
} else {
for(ICpItem p : processors.values()) {
props.addChild(p);
}
}
// add other properties
collectEffectiveProperties(processorName, props);
return props;
}
protected int collectEffectiveProperties(String pname, ICpItem props) {
int nseq = 0;
// insert properties starting from this item and going up in parent chain
for(ICpDeviceItem deviceItem = this; deviceItem != null; deviceItem = deviceItem.getDeviceItemParent()){
props.attributes().mergeAttributes(deviceItem.attributes());
Collection<? extends ICpItem> children = deviceItem.getChildren();
if(children == null) {
continue;
}
for(ICpItem p : children) {
String itemPname = p.getProcessorName();
if(pname == null || pname.isEmpty() || itemPname.isEmpty() || itemPname.equals(pname)) {
props.mergeProperty(p, pname);
}
}
}
return nseq;
}
@Override
public synchronized ICpDebugConfiguration getDebugConfiguration(String processorName) {
if(debugConfigurations == null) {
// ensure filled processor collection
getProcessors();
// collect properties for all processors
debugConfigurations = new HashMap<String, ICpDebugConfiguration>();
for(Entry<String, ICpItem> e : processors.entrySet()) {
String pname = e.getKey();
CpDebugConfiguration debugConfig = new CpDebugConfiguration(this);
ICpItem processor = getProcessor(pname);
// add processor attribute to the configuration
if(processor != null ) {
debugConfig.attributes().setAttributes(processor.attributes());
}
debugConfigurations.put(pname, debugConfig);
debugConfig.init( getEffectiveProperties(pname));
}
}
return debugConfigurations.get(processorName);
}
@Override
protected String constructName() {
switch(getLevel()) {
case DEVICE:
return getAttribute(CmsisConstants.DNAME);
case FAMILY:
return getAttribute(CmsisConstants.DFAMILY);
case SUBFAMILY:
return getAttribute(CmsisConstants.DSUBFAMILY);
case VARIANT:
return getAttribute(CmsisConstants.DVARIANT);
default:
break;
}
return super.constructName();
}
@Override
public String getLevelName(EDeviceHierarchyLevel level) {
switch(level) {
case VENDOR:
return getEffectiveAttribute(CmsisConstants.DVENDOR);
case DEVICE:
return getEffectiveAttribute(CmsisConstants.DNAME);
case FAMILY:
return getEffectiveAttribute(CmsisConstants.DFAMILY);
case SUBFAMILY:
return getEffectiveAttribute(CmsisConstants.DSUBFAMILY);
case VARIANT:
return getEffectiveAttribute(CmsisConstants.DVARIANT);
default:
break;
}
return null;
}
@Override
public String constructId() {
return getName();
}
@Override
public boolean hasEffectiveChildren() {
return getEffectiveChildCount() > 0;
}
@Override
public Collection<? extends ICpItem> getEffectiveChildren() {
// combination of direct properties and device children
List<ICpItem> effectiveChildren = new LinkedList<ICpItem>();
if(hasChildren()) {
effectiveChildren.addAll(getChildren());
}
if(hasDeviceItems()) {
effectiveChildren.addAll(getDeviceItems());
}
return effectiveChildren;
}
@Override
public int getEffectiveChildCount() {
int count = getChildCount(); // count of direct properties
if(hasDeviceItems()) {
count += getDeviceItems().size();
}
return count;
}
@Override
protected Object[] createChildArray() {
// use cached array for effective children, while direct children are rarely needed in GUI
Collection<? extends ICpItem> collection = getEffectiveChildren();
if(collection != null && !collection.isEmpty()) {
return collection.toArray();
}
return EMPTY_OBJECT_ARRAY;
}
@Override
protected Collection<? extends ICpItem> getItemsToVisit() {
return getEffectiveChildren();
}
@Override
public synchronized String getUrl() {
if(fURL == null) {
fURL = DeviceVendor.getVendorUrl(getVendor());
if(!fURL.isEmpty()) {
fURL += '/';
fURL += DeviceVendor.adjutsToUrl(getName());
}
}
return fURL;
}
@Override
public String getDoc() {
//get first book
String doc = null;
ICpItem bookItem = getFirstChild(CmsisConstants.BOOK_TAG);
if(bookItem != null) {
doc = bookItem.getDoc();
}
if(doc == null || doc.isEmpty()) {
doc = super.getDoc();
}
return doc;
}
@Override
public ICpDeviceItem findDeviceByName(String deviceName, int eDeviceHierarchyLevel) {
if (getName().equals(deviceName) && level.ordinal() == eDeviceHierarchyLevel) {
return this;
}
if (level.ordinal() > eDeviceHierarchyLevel) {
return null;
}
if (getDeviceItems() != null) {
for (ICpDeviceItem device : getDeviceItems()) {
ICpDeviceItem d = device.findDeviceByName(deviceName, eDeviceHierarchyLevel);
if (d != null) {
return d;
}
}
}
return null;
}
}