package dongfang.mkt.configuration;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class ConfigSet
{
public static final int NUMBER_OF_VARIABLES =
8;
String name
;
int eepromVersion
;
List<Section
> declaredSections =
new ArrayList<Section
>();
List<ConfigEntry
> entries =
new ArrayList<ConfigEntry
>();
public static class Section
{
String name, title
;
List<ConfigEntry
> entries =
new ArrayList<ConfigEntry
>();
public Section
(String name,
String title
) {
this.
name = name
;
this.
title = title
;
}
public void addConfigEntry
(ConfigEntry e
) {
this.
entries.
add(e
);
}
public List<ConfigEntry
> getEntries
() {
return entries
;
}
public String getName
() {
return name
;
}
public String getTitle
() {
return title
;
}
}
public static abstract class ConfigEntry
{
String name
;
ConfigEntry
(String name
) {
this.
name = name
;
}
abstract int getByteCount
();
abstract String toStringWithValues
();
abstract void toXML
(StringBuilder result
);
abstract int setValue
(int[] data,
int offset
);
public String getName
() {
return name
;
}
public String getSection
() {
return name
;
}
}
public static class StaticByteEntry
extends ConfigEntry
{
StaticByteEntry
(String name
) {
super(name
);
}
int value
;
int getByteCount
() {
return 1;
}
int getValue
() {
return value
;
}
int setValue
(int[] data,
int offset
) {
this.
value = data
[offset
];
return getByteCount
();
}
String toStringWithValues
() {
return name +
":\t" + value
;
}
void toXML
(StringBuilder result
) {
String s_value
;
s_value =
Integer.
toString(value
);
result.
append(" <parameter name=\"" + name +
"\" value=\""
+ s_value +
"\"/>\n");
}
}
public static class DynamicByteEntry
extends StaticByteEntry
{
int minValue =
0;
int maxValue =
255;
String staticCodeName
;
String dynamicCodeName
;
DynamicByteEntry
(String name
) {
super(name
);
}
int getMinValue
() {
return minValue
;
}
int getMaxValue
() {
return maxValue
;
}
void setMinValue
(int minValue
) {
this.
minValue = minValue
;
}
void setMaxValue
(int maxValue
) {
this.
maxValue = maxValue
;
}
String getStaticCodeName
() {
return staticCodeName
;
}
String getDynamicCodeName
() {
return dynamicCodeName
;
}
void setStaticCodeName
(String staticCodeName
) {
this.
staticCodeName = staticCodeName
;
}
void setDynamicCodeName
(String dynamicCodeName
) {
this.
dynamicCodeName = dynamicCodeName
;
}
void toXML
(StringBuilder result
) {
String s_value
;
int numberOfLowestVariable =
256 - NUMBER_OF_VARIABLES
;
if (value
>= numberOfLowestVariable
) {
s_value =
"var" +
(value - numberOfLowestVariable
);
} else
s_value =
Integer.
toString(value
);
result.
append(" <parameter name=\"" + name +
"\" value=\""
+ s_value +
"\"/>\n");
}
}
public static class BitSetEntry
extends ConfigEntry
{
BitSetEntry
(String name,
String[] bitNames
) {
super(name
);
this.
bitNames = bitNames
;
}
int value
;
String[] bitNames
;
int getByteCount
() {
return 1;
}
int getValue
() {
return value
;
}
int setValue
(int[] data,
int offset
) {
value = data
[offset
];
return getByteCount
();
}
String toStringWithValues
() {
StringBuilder result =
new StringBuilder(name +
"\t[");
for (int i =
0; i
< Math.
min(bitNames.
length,
8); i++
) {
if (i
!=
0)
result.
append(", ");
result.
append(bitNames
[i
] +
":"
+
((value
& (1 << i
)) !=
0 ? "1" :
"0"));
}
return result.
toString();
}
void toXML
(StringBuilder result
) {
result.
append(" <parameter name=\"" + name +
"\">\n");
for (int i =
0; i
< Math.
min(bitNames.
length,
8); i++
) {
result.
append(" <bit name=\"" + bitNames
[i
] +
"\" value=\""
+
((value
& (1 << i
)) !=
0 ? "1" :
"0") +
"\"/>\n");
}
result.
append(" </parameter>\n");
}
}
public static class ArrayEntry
extends ConfigEntry
{
int length
;
boolean isDynamic
;
int[] values
;
ArrayEntry
(String name,
boolean isDynamic,
int length
) {
super(name
);
this.
isDynamic = isDynamic
;
this.
length = length
;
}
int[] getValue
() {
return values
;
}
int setValue
(int[] data,
int offset
) {
values =
new int[length
];
System.
arraycopy(data, offset, values,
0, length
);
return length
;
}
int getByteCount
() {
return length
;
}
String toStringWithValues
() {
StringBuilder result =
new StringBuilder(name +
":\t{");
for (int i =
0; i
< length
; i++
) {
if (i
!=
0)
result.
append(",");
result.
append(values
[i
]);
}
result.
append("}");
return result.
toString();
}
void toXML
(StringBuilder result
) {
result.
append(" <list name=\"" + name +
"\">\n");
for (int i =
0; i
< length
; i++
) {
result.
append(" <entry value=\"" + values
[i
] +
"\"/>\n");
}
result.
append(" </list>\n");
}
}
public List<ConfigEntry
> getEntries
() {
return entries
;
}
public List<Section
> getDeclaredSections
() {
return declaredSections
;
}
public void setData
(int[] data
) throws IOException {
int offset =
0;
int dataLength = data.
length -
12;
if (dataLength
!= getByteCount
()) {
throw new IOException("The received number of databytes (" + dataLength +
") was not equal to the length of the declared parameter set(" + getByteCount
()+
").");
}
for (ConfigEntry entry : entries
) {
offset += entry.
setValue(data, offset
);
}
StringBuilder sbname =
new StringBuilder();
for (int i =
0; i
< 12; i++
) {
if (data
[offset
] ==
0)
break;
sbname.
append((char) data
[offset++
]);
}
name = sbname.
toString();
}
public int getByteCount
() {
int result =
0;
for (ConfigEntry e : entries
) {
result += e.
getByteCount();
}
return result
;
}
public String toStringWithValues
() {
StringBuilder result =
new StringBuilder();
result.
append(name +
"\n");
for (ConfigEntry entry : entries
) {
result.
append(entry.
toStringWithValues() +
"\n");
}
return result.
toString();
}
public String toXML
() {
StringBuilder result =
new StringBuilder();
result.
append("<parameterset eepromVersion=\"" + eepromVersion
+
"\" length=\"" + getByteCount
() +
"\">\n");
for (int i =
0; i
< entries.
size(); i++
) {
ConfigEntry entry = entries.
get(i
);
entry.
toXML(result
);
}
result.
append("</parameterset>\n");
return result.
toString();
}
public ConfigSet
(int eepromVersion
) {
super();
this.
eepromVersion = eepromVersion
;
}
// This parses only for the purpose of naming and typing parameter sets!
// It does not parse the section and default information, which could be
// useful for GUIs etc.
public static ConfigSet parseXMLConfigSet
(int version
) throws IOException {
String fileName =
"configsets/templates/v" + version +
".xml";
File f =
new File(fileName
);
DocumentBuilderFactory saxfac =
DocumentBuilderFactory.
newInstance();
saxfac.
setValidating(false);
try {
DocumentBuilder bldr = saxfac.
newDocumentBuilder();
Document doc = bldr.
parse(f
);
XPath xpath =
XPathFactory.
newInstance().
newXPath();
String s_eepromVersion = xpath.
evaluate(
"/parametertemplate/@eepromVersion", doc
);
int eepromVersion =
Integer.
parseInt(s_eepromVersion
);
String s_declaredLength = xpath.
evaluate(
"/parametertemplate/@length", doc
);
int declaredLength =
Integer.
parseInt(s_declaredLength
);
if (eepromVersion
!= version
) {
throw new IOException(
"Version mismatch between file name ("
+ fileName
+
") and the version in the parametertemplate/@eepromVersion attribute("
+ s_eepromVersion +
")");
}
ConfigSet result =
new ConfigSet
(eepromVersion
);
NodeList sectionNodes =
(NodeList) xpath.
evaluate(
"/parametertemplate/section", doc,
XPathConstants.
NODESET);
for (int i =
0; i
< sectionNodes.
getLength(); i++
) {
Element sectionNode =
(Element) sectionNodes.
item(i
);
Section section =
new Section
(sectionNode.
getAttribute("name"),
sectionNode.
getAttribute("title"));
result.
declaredSections.
add(section
);
NodeList parameterNodes =
(NodeList) xpath.
evaluate(
"parameter", sectionNode,
XPathConstants.
NODESET);
for (int j =
0; j
< parameterNodes.
getLength(); j++
) {
Element parameterNode =
(Element) parameterNodes.
item(j
);
ConfigEntry entry
;
if (!sectionNode.
hasAttribute("name")) {
throw new IOException("A parameter element (the " + j
+
"th in section "
+ sectionNode.
getAttribute("name")
+
") had no name attribute!");
}
String s_name = parameterNode.
getAttribute("name");
String s_type
;
if (parameterNode.
hasAttribute("type")) {
s_type = parameterNode.
getAttribute("type");
} else {
s_type =
"static";
}
if ("static".
equals(s_type
)) {
entry =
new ConfigSet.
StaticByteEntry(s_name
);
} else if ("dynamic".
equals(s_type
)) {
ConfigSet.
DynamicByteEntry de =
new ConfigSet.
DynamicByteEntry(s_name
);
if (parameterNode.
hasAttribute("minValue")) {
de.
setMinValue(Integer.
parseInt(parameterNode.
getAttribute("minValue")));
}
if (parameterNode.
hasAttribute("maxValue")) {
de.
setMinValue(Integer.
parseInt(parameterNode.
getAttribute("maxValue")));
}
if (parameterNode.
hasAttribute("staticCodeName")) {
de.
setStaticCodeName(parameterNode.
getAttribute("staticCodeName"));
} else de.
setStaticCodeName(de.
getName());
if (parameterNode.
hasAttribute("dynamicCodeName")) {
de.
setDynamicCodeName(parameterNode.
getAttribute("dynamicCodeName"));
} else de.
setDynamicCodeName(de.
getName());
entry = de
;
} else if ("bitset".
equals(s_type
)) {
NodeList bitNodes =
(NodeList) xpath.
evaluate("bit",
parameterNode,
XPathConstants.
NODESET);
String[] bitNames =
new String[8];
for (int k =
0; k
< 8; k++
) {
Element bitNode =
(Element) bitNodes.
item(k
);
if (bitNode
!=
null) {
bitNames
[k
] = bitNode.
getAttribute("name");
} else {
bitNames
[k
] =
"Unused";
}
}
entry =
new ConfigSet.
BitSetEntry(s_name, bitNames
);
} else {
throw new IOException("Unknown parameter type: "
+ s_type
);
}
result.
entries.
add(entry
);
section.
addConfigEntry(entry
);
}
}
result.
name =
"" + version
;
if (result.
getByteCount() != declaredLength
) {
throw new IOException("The number of parameters in the set (" + result.
getEntries().
size() +
") was not equal to the declared length (" + declaredLength +
").");
}
return result
;
} catch (IOException ex
) {
throw ex
;
} catch (XPathExpressionException ex
) {
throw new IOException(ex
);
} catch (SAXException ex
) {
throw new IOException(ex
);
} catch (ParserConfigurationException ex
) {
throw new IOException(ex
);
}
}
public String generateDynamicSubstitutionCode
() {
StringBuilder result =
new StringBuilder(
"const MMXLATION XLATIONS[] = {\n");
boolean hasEntries =
false;
for (ConfigEntry entry : entries
) {
if (entry
instanceof ConfigSet.
DynamicByteEntry) {
if (hasEntries
)
result.
append(",\n");
else
hasEntries =
true;
ConfigSet.
DynamicByteEntry de =
(ConfigSet.
DynamicByteEntry) entry
;
result.
append("{offsetof(ParamSet_t, ");
result.
append(de.
getStaticCodeName());
result.
append("), offsetof(DynamicParams_t, ");
result.
append(de.
getDynamicCodeName());
result.
append("),");
result.
append(Integer.
toString(de.
getMinValue()));
result.
append(",");
result.
append(Integer.
toString(de.
getMaxValue()));
result.
append("}");
}
}
result.
append("};");
return result.
toString();
}
}