/*******************************************************************************
* Copyright (c) 2008, 2011 Thomas Holland (thomas@innot.de) 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:
* Thomas Holland - initial API and implementation
*******************************************************************************/
package de.innot.avreclipse.core.toolinfo.fuses;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import de.innot.avreclipse.AVRPlugin;
/**
* {@link IMCUDescription} implementation for FuseBytes.
* <p>
* Objects of this class hold the {@link BitFieldDescription} objects for all fuse bytes of a single
* MCU.
* </p>
*
* @author Thomas Holland
* @since 2.2
*
*/
public class MCUDescription implements IMCUDescription {
private final static String ELEMENT_ROOT = "description";
private final static String ATTR_ROOT_MCUTYPE = "mcutype";
private final static String ELEMENT_VERSION = "version";
private final static String ATTR_VERSION_BUILD = "build";
/** The MCU for this description. */
private String fMCUid;
/**
* The build number from the Part Description File. As of AVR Studio 5.0 this is the date of the
* last modification of the source file.
*/
private int fBuildVersion;
/** The list of Fuse byte descriptions. */
private final List<ByteDescription> fFuseByteDescList;
/** The list of Lockbits byte descriptions. */
private final List<ByteDescription> fLockbitsByteDescList;
/**
* Create a new MCUDescription for a MCU with the given number of fuse bytes.
*
* @param mcuid
* <code>String</code> with a MCU id value.
* @param bytecount
* <code>int</code> with the number of fuse bytes this MCU has.
*/
public MCUDescription(String mcuid) {
fMCUid = mcuid;
fFuseByteDescList = new ArrayList<ByteDescription>();
fLockbitsByteDescList = new ArrayList<ByteDescription>();
}
public MCUDescription(Document document) throws IllegalArgumentException {
fMCUid = null;
fFuseByteDescList = new ArrayList<ByteDescription>();
fLockbitsByteDescList = new ArrayList<ByteDescription>();
// Default attribute values for the <version> element.
// Used when these attributes are missing from the xml file.
fBuildVersion = 0;
// Get the root node and read the attributes
NodeList nodes = document.getElementsByTagName(ELEMENT_ROOT);
if (nodes.getLength() != 1) {
throw new IllegalArgumentException("No root node <" + ELEMENT_ROOT + "> found.");
}
Node rootnode = nodes.item(0);
NamedNodeMap attrs = rootnode.getAttributes();
// The root node has one attributes: "mcutype". Must be present and valid.
Node mcutypenode = attrs.getNamedItem(ATTR_ROOT_MCUTYPE);
if (mcutypenode != null) {
fMCUid = mcutypenode.getTextContent();
} else {
throw new IllegalArgumentException("required attribute \"" + ATTR_ROOT_MCUTYPE
+ "\" is missing from the <" + ELEMENT_ROOT + "> element.");
}
// read the <version> element (only first one if multiple elements are present).
NodeList versionnodes = document.getElementsByTagName(ELEMENT_VERSION);
if (versionnodes.getLength() > 0) {
// The <version> element has one attribute: "build".
// The "status" attribute is deprecated and ignored
attrs = versionnodes.item(0).getAttributes();
for (int i = 0; i < attrs.getLength(); i++) {
Node attr = attrs.item(i);
if (ATTR_VERSION_BUILD.equalsIgnoreCase(attr.getNodeName())) {
fBuildVersion = Integer.decode(attr.getNodeValue());
}
}
}
// read the <fusebyte> elements
NodeList bytenodes = document.getElementsByTagName(FuseType.FUSE.getElementName());
for (int i = 0; i < bytenodes.getLength(); i++) {
ByteDescription bd = new ByteDescription(bytenodes.item(i));
addByteDescription(FuseType.FUSE, bd);
}
// and the <lockbitsbyte> elements.
bytenodes = document.getElementsByTagName(FuseType.LOCKBITS.getElementName());
for (int i = 0; i < bytenodes.getLength(); i++) {
ByteDescription bd = new ByteDescription(bytenodes.item(i));
addByteDescription(FuseType.LOCKBITS, bd);
}
}
/*
* (non-Javadoc)
* @see de.innot.avreclipse.core.toolinfo.fuses.IMCUDescription#getMCUId()
*/
public String getMCUId() {
return fMCUid;
}
/*
* (non-Javadoc)
* @see de.innot.avreclipse.core.toolinfo.fuses.IMCUDescription#getVersion()
*/
public int getVersion() {
return fBuildVersion;
}
/**
* Set the build version and the status as defined by the part description file.
*
* @param buildversion
*/
public void setVersion(int buildversion) {
fBuildVersion = buildversion;
}
/*
* (non-Javadoc)
* @see
* de.innot.avreclipse.core.toolinfo.fuses.IMCUDescription#getByteCount(de.innot.avreclipse.
* core.toolinfo.fuses.FuseType)
*/
public int getByteCount(FuseType type) {
switch (type) {
case FUSE:
return fFuseByteDescList.size();
case LOCKBITS:
return fLockbitsByteDescList.size();
default:
IStatus status = new Status(IStatus.ERROR, AVRPlugin.PLUGIN_ID,
"Internal error: undefined fuse memory type " + type.toString(), null);
AVRPlugin.getDefault().log(status);
return 0;
}
}
/*
* (non-Javadoc)
* @see
* de.innot.avreclipse.core.toolinfo.fuses.IMCUDescription#getByteDescription(java.lang.String)
*/
public IFuseObjectDescription getByteDescription(String name) {
// go thru both fusebytes and lockbitsbyte list and see if we can find a match.
for (ByteDescription bd : fFuseByteDescList) {
if (bd.getName().equalsIgnoreCase(name)) {
return bd;
}
}
for (ByteDescription bd : fLockbitsByteDescList) {
if (bd.getName().equalsIgnoreCase(name)) {
return bd;
}
}
return null;
}
/*
* (non-Javadoc)
* @see
* de.innot.avreclipse.core.toolinfo.fuses.IMCUDescription#getByteDescription(de.innot.avreclipse
* .core.toolinfo.fuses.FuseType, int)
*/
public IFuseObjectDescription getByteDescription(FuseType type, int index) {
switch (type) {
case FUSE:
return fFuseByteDescList.get(index);
case LOCKBITS:
return fLockbitsByteDescList.get(index);
default:
return null;
}
}
/*
* (non-Javadoc)
* @see
* de.innot.avreclipse.core.toolinfo.fuses.IMCUDescription#getByteDescriptions(de.innot.avreclipse
* .core.toolinfo.fuses.FuseType)
*/
public List<IFuseObjectDescription> getByteDescriptions(FuseType type) {
switch (type) {
case FUSE:
return new ArrayList<IFuseObjectDescription>(fFuseByteDescList);
case LOCKBITS:
return new ArrayList<IFuseObjectDescription>(fLockbitsByteDescList);
default:
IStatus status = new Status(IStatus.ERROR, AVRPlugin.PLUGIN_ID,
"Internal error: undefined fuse memory type " + type.toString(), null);
AVRPlugin.getDefault().log(status);
return null;
}
}
public void addByteDescription(FuseType type, ByteDescription desc) {
int index = desc.getIndex();
List<ByteDescription> list = null;
switch (type) {
case FUSE:
list = fFuseByteDescList;
break;
case LOCKBITS:
list = fLockbitsByteDescList;
break;
default:
IStatus status = new Status(IStatus.ERROR, AVRPlugin.PLUGIN_ID,
"Internal error: undefined fuse memory type " + type.toString(), null);
AVRPlugin.getDefault().log(status);
return;
// do nothing
}
while (index >= list.size()) {
list.add(null);
}
list.set(index, desc);
}
/**
* Convert this MCUDescription Object to XML.
* <p>
* This method is used to serialize the descriptions to a XML DOM tree. Saving the DOM tree to a
* file is left to the caller.
* </p>
* <p>
* The DTD format of the created content:
*
* <pre>
* <!ELEMENT fuse ( version, byte+ ) >
* <!ATTLIST fuse bytecount NMTOKEN #REQUIRED >
* <!ATTLIST fuse mcutype NMTOKEN #REQUIRED >
*
* <!ELEMENT version EMPTY >
* <!ATTLIST version build NMTOKEN #REQUIRED >
* <!ATTLIST version status NMTOKEN #REQUIRED >
*
* <!ELEMENT byte ( default, bitfield+ ) >
* <!ATTLIST byte index NMTOKEN #REQUIRED >
* <!ATTLIST byte name NMTOKEN #REQUIRED >
*
* <!ELEMENT default EMPTY >
* <!ATTLIST default value NMTOKEN #REQUIRED >
*
* <!ELEMENT bitfield ( value* ) >
* <!ATTLIST bitfield desc CDATA #REQUIRED >
* <!ATTLIST bitfield mask NMTOKEN #REQUIRED >
* <!ATTLIST bitfield name ID #REQUIRED >
*
* <!ELEMENT value EMPTY >
* <!ATTLIST value desc CDATA #REQUIRED >
* <!ATTLIST value val NMTOKEN #REQUIRED >
*
* </pre>
*
* </p>
*
* @param document
* a blank DOM document to write the content to
*/
public void toXML(Document document) {
Element rootnode = document.createElement(ELEMENT_ROOT);
rootnode.setAttribute(ATTR_ROOT_MCUTYPE, fMCUid);
document.appendChild(rootnode);
// Set the version and release status
Element versionnode = document.createElement(ELEMENT_VERSION);
versionnode.setAttribute(ATTR_VERSION_BUILD, Integer.toString(fBuildVersion));
rootnode.appendChild(versionnode);
// Now a <fusebyte> element for each fusebytes
for (ByteDescription bd : fFuseByteDescList) {
if (bd != null) {
bd.toXML(rootnode);
}
}
// and the same for the lockbit bytes
for (ByteDescription bd : fLockbitsByteDescList) {
if (bd != null) {
bd.toXML(rootnode);
}
}
}
/*
* (non-Javadoc)
* @see
* de.innot.avreclipse.core.toolinfo.fuses.IMCUDescription#isCompatibleWith(de.innot.avreclipse
* .core.toolinfo.fuses.IMCUDescription, de.innot.avreclipse.core.toolinfo.fuses.FuseType)
*/
public boolean isCompatibleWith(IMCUDescription target, FuseType type) {
// First check the byte count. If they differ, then it can not be compatible
if (getByteCount(type) != target.getByteCount(type)) {
return false;
}
// Next get a list of all ByteDescription Objects and compare them each
List<IFuseObjectDescription> ourlist = getByteDescriptions(type);
List<IFuseObjectDescription> targetlist = target.getByteDescriptions(type);
for (int i = 0; i < ourlist.size(); i++) {
IFuseObjectDescription ourbyte = ourlist.get(i);
IFuseObjectDescription targetbyte = targetlist.get(i);
if (ourbyte == null) {
return targetbyte == null;
}
if (!ourbyte.isCompatibleWith(targetbyte)) {
return false;
}
}
// all bytes matched -> success
return true;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder("Fuses Description for " + getMCUId());
sb.append(" [");
sb.append(" build version " + fBuildVersion);
sb.append(" Fuses: ");
for (IFuseObjectDescription bd : fFuseByteDescList) {
sb.append("[" + bd.toString() + "]");
}
sb.append(" Fuses: ");
for (IFuseObjectDescription bd : fFuseByteDescList) {
sb.append("[" + bd.toString() + "]");
}
sb.append(" Lockbits: ");
for (IFuseObjectDescription bd : fLockbitsByteDescList) {
sb.append("[" + bd.toString() + "]");
}
sb.append(" ]");
return sb.toString();
}
}