Skip to content

Commit

Permalink
Merge pull request #267 from bobjacobsen/bobjacobsen-add-actions-to-CDI
Browse files Browse the repository at this point in the history
Improvements to CDI element support
  • Loading branch information
dpharris authored Aug 18, 2024
2 parents 63a5ac6 + d1fbff2 commit 20a8b8d
Show file tree
Hide file tree
Showing 6 changed files with 504 additions and 71 deletions.
59 changes: 49 additions & 10 deletions sample.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="XSLT/decoder.xsl"?>
<cdi>
<cdi xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://openlcb.org/schema/cdi/1/4/cdi.xsd">

<identification>
<manufacturer>Spacely Sprockets</manufacturer>
Expand All @@ -24,30 +25,68 @@
<description>The EventIDs for the consumers</description>
<eventid/>
<eventid/>
<blob size="10" mode="readwrite">
<name>Blob to see if works in group element</name>
</blob>
</group>
<bit>
<name>Sample bit variable</name>
<description>Doesn't do anything</description>
</bit>
<int size="2">
<name>Sample integer variable</name>
<description>Doesn't do anything</description>
<min>1</min>
<max>999</max>
<default>12</default>
</int>
<int size="2">
<name>Sample integer slider</name>
<description>Doesn't do anything either</description>
<min>0</min>
<max>1000</max>
<default>12</default>
<hints>
<slider divisions="5" />
</hints>
</int>
</segment>

<segment origin="128" space="1">
<int size="1">
<name>Reset</name>
<description>Controls reloading and clearing node memory. Board must be restarted for this to take effect.</description>
<name>Reset via Map</name>
<description>
Controls reloading and clearing node memory.
Board must be restarted for this to take effect.
</description>
<map>
<relation><property>85</property><value>(No reset)</value></relation>
<relation><property>0</property><value>Reset all to defaults</value></relation>
<relation><property>170</property><value>Reset just EventIDs to defaults</value></relation>
<relation><property>0</property><value>No reset (0)</value></relation>
<relation><property>85</property><value>Reset just EventIDs to defaults (85)</value></relation>
<relation><property>170</property><value>Reset all to defaults (170)</value></relation>
</map>
</int>
<int size="1" offset="-1">
<name>Reset Directly</name>
<description>
This accesses the same memory location as the
mapped variable just above.
</description>
</int>
<action size="2">
<name>Factory Reset via address 129</name>
<buttonText>Perform Reset</buttonText>
<dialogText>Do a factory reset?</dialogText>
<value>2</value>
</action>
<action size="2" offset="-2">
<name>Reboot via address 129</name>
<buttonText>Perform Reboot</buttonText>
<dialogText></dialogText> <!-- no dialog -->
<value>9</value>
</action>
<blob size="10" mode="readwrite">
<name>Blob defined at address 131</name>
</blob>
<int size="1">
<name>Yet Another Reset</name>
<description>This should be stored at address 141.</description>
</int>
</segment>

</cdi>
18 changes: 0 additions & 18 deletions sample2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,6 @@
<eventid />
<eventid />
</group>
<bit>
<name>Regular bit variable</name>
<description>Demonstrate how a standard bit (boolean) variable can be shown</description>
</bit>
<bit>
<name>Bit variable with named states</name>
<description>Demonstrate how a map relabels the states of a bit (boolean) variable</description>
<map>
<relation>
<property>true</property>
<value>Lit</value>
</relation>
<relation>
<property>false</property>
<value>Not Lit</value>
</relation>
</map>
</bit>
</segment>
<segment space="1" origin="128">
<name>Resets</name>
Expand Down
27 changes: 27 additions & 0 deletions src/org/openlcb/cdi/CdiRep.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,25 +79,52 @@ public static interface Map {
* @return a list of all user-visible values.
*/
public java.util.List<String> getValues();

/**
* Add an item to the map. Useful if e.g. a non-mapped
* value is found in a location.
*/
public void addItemToMap(String key, String entry);
}

public static interface EventID extends Item {
}

public static interface IntegerRep extends Item {
public int getDefault();
public long getMin();
public long getMax();

public int getSize();

public boolean isSliderHint();
public int getSliderDivisions();
}

public static interface BitRep extends Item {
public boolean getDefault();

public int getSize();
}

public static interface UnknownRep extends Item {
public boolean getDefault();

public int getSize();
}

public static interface StringRep extends Item { // "String" causes too many name conflicts

public int getSize();
}

public static interface ActionButtonRep extends Item {

public long getValue();
public String getButtonText();
public String getDialogText();

public int getSize();
}

}
109 changes: 109 additions & 0 deletions src/org/openlcb/cdi/impl/ConfigRepresentation.java
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ private long processGroup(String baseName, int segment, List<CdiRep.Item> items,
entry = new EventEntry(name, (CdiRep.EventID) it, segment, origin);
} else if (it instanceof CdiRep.StringRep) {
entry = new StringEntry(name, (CdiRep.StringRep) it, segment, origin);
} else if (it instanceof CdiRep.ActionButtonRep) {
entry = new ActionButtonEntry(name, (CdiRep.ActionButtonRep) it, segment, origin);
} else if (it instanceof CdiRep.UnknownRep) {
entry = new UnknownEntry(name, (CdiRep.UnknownRep) it, segment, origin);
} else {
logger.log(Level.SEVERE, "could not process CDI entry type of {0}", it);
}
Expand Down Expand Up @@ -303,12 +307,16 @@ public void visitEntry(CdiEntry e) {
visitInt((IntegerEntry) e);
} else if (e instanceof EventEntry) {
visitEvent((EventEntry) e);
} else if (e instanceof ActionButtonEntry) {
visitActionButton((ActionButtonEntry) e);
} else if (e instanceof GroupRep) {
visitGroupRep((GroupRep) e);
} else if (e instanceof GroupEntry) {
visitGroup((GroupEntry) e);
} else if (e instanceof SegmentEntry) {
visitSegment((SegmentEntry) e);
} else if (e instanceof UnknownEntry) {
visitUnknown((UnknownEntry) e);
} else if (e instanceof CdiContainer) {
visitContainer((CdiContainer) e);
} else {
Expand All @@ -331,6 +339,10 @@ public void visitEvent(EventEntry e) {
visitLeaf(e);
}

public void visitActionButton(ActionButtonEntry e) {
visitLeaf(e);
}

public void visitGroupRep(GroupRep e) {
visitContainer(e);
}
Expand All @@ -343,6 +355,10 @@ public void visitSegment(SegmentEntry e) {
visitContainer(e);
}

public void visitUnknown(UnknownEntry e) {
visitLeaf(e);
}

public void visitContainer(CdiContainer c) {
for (CdiEntry e : c.getEntries()) {
visitEntry(e);
Expand Down Expand Up @@ -700,4 +716,97 @@ public void setValue(String value) {
}
}

/**
* Represents an unknown variable, perhaps due to a more-recent schema
*/
public class UnknownEntry extends CdiEntry {
public CdiRep.UnknownRep rep;

UnknownEntry(String name, CdiRep.UnknownRep rep, int segment, long origin) {
this.key = name;
this.space = segment;
this.origin = origin;
this.rep = rep;
this.size = rep.getSize();
}

@Override
public CdiRep.Item getCdiItem() {
return rep;
}

@Override
protected void updateVisibleValue() {
lastVisibleValue = getValue();
}

@Override
public boolean isNullTerminated() {
return size > 64;
}

public String getValue() {
MemorySpaceCache cache = getCacheForSpace(space);
byte[] b = cache.read(origin, size);
if (b == null) return null;
// We search for a terminating null byte and clip the string there.
int len = 0;
while (len < b.length && b[len] != 0) ++len;
byte[] rep = new byte[len];
System.arraycopy(b, 0, rep, 0, len);
String ret = new String(rep, UTF8);
return ret;
}

public void setValue(String value) {
MemorySpaceCache cache = getCacheForSpace(space);
byte[] f;
f = value.getBytes(UTF8);
byte[] b = new byte[Math.min(size, f.length + 1)];
System.arraycopy(f, 0, b, 0, Math.min(f.length, b.length - 1));
cache.write(this.origin, b, this);
}
}

/**
* Represents an action button variable.
*/
public class ActionButtonEntry extends CdiEntry {
public CdiRep.ActionButtonRep rep;

ActionButtonEntry(String name, CdiRep.ActionButtonRep rep, int segment, long origin) {
this.key = name;
this.space = segment;
this.origin = origin;
this.rep = rep;
this.size = rep.getSize();
}

@Override
public CdiRep.Item getCdiItem() {
return rep;
}

@Override
protected void updateVisibleValue() {
// does nothing in this class
}

public long getValue() {
// should not be called
logger.log(Level.SEVERE, "ActionButtonEntry.getValue should not be called");
return -1;
}

public void setValue(long value) {
MemorySpaceCache cache = getCacheForSpace(space);
byte[] b = new byte[size];
for (int i = size - 1; i >= 0; --i) {
b[i] = (byte)(value & 0xff);
value >>= 8;
}
cache.write(origin, b, this);
}
}

}
Loading

0 comments on commit 20a8b8d

Please sign in to comment.