Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion manifest
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Manifest-Version: 1.0
Main-Class: scenarios.ScenarioRunner
Class-Path: lib/junit.jar lib/jdom-2.0.5.jar lib/jdom.jar lib/jlfgr-1_0.jar
Class-Path: lib/junit.jar lib/jdom2-2.0.6.jar lib/jlfgr-1_0.jar lib/xercesImpl.jar

Name: org.openlcb
Specification-Title: OpenLCB
Expand Down
190 changes: 190 additions & 0 deletions src/org/openlcb/EventID.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ public EventID(@NonNull String value) {
System.arraycopy(data, 0, this.contents, 0, BYTECOUNT);
}

// note long's 64th bit is a sign
@CheckReturnValue
public EventID(long value) {
this.contents = new byte[BYTECOUNT];
for (int index = 0; index < 8; index++) {
contents[index] = (byte)((value>>(8*(7-index))) & 0xFF);
}
}

byte[] contents;

@CheckReturnValue
Expand Down Expand Up @@ -117,4 +126,185 @@ public long toLong() {
}
return ret;
}

/**
* Take the eventID from a range, and return
* the lower flag bytes as a hex dotted string.
* @return the lower flag bytes
*/
public long rangeSuffix() {
// find the mask value
long eid = this.toLong();
long sampleBit = eid & 0x01;
long mask = 0L;
while ( (eid &0x01L) == sampleBit) {
mask = (mask <<1) | 0x01;
eid = eid >> 1;
}
return mask;
}


/**
* Decode well-known and specifically defined event IDs
* @return "" if nothing interesting about the event
*/
public String parse() {
String eid = this.toShortString().substring(0, 2);
switch (eid) {
case "00":
return reserved();
case "01":
return wellKnown();
case "09":
if (this.toShortString().startsWith("09.00.99.FF")) {
return trainSearch();
}
// deliberately falling through
//$FALL-THROUGH$
default:
return "";
}
}

protected String reserved() {
return "Reserved "+this.toShortString();
}

protected String wellKnown() {
String eid = this.toShortString();
switch (eid) {
case "01.00.00.00.00.00.FF.FF":
return "Emergency off";
case "01.00.00.00.00.00.FF.FE":
return "Clear Emergency Off";
case "01.00.00.00.00.00.FF.FD":
return "Emergency stop of all operations";
case "01.00.00.00.00.00.FF.FC":
return "Clear emergency stop of all operations";
case "01.00.00.00.00.00.FF.F8":
return "Node recorded a new log entry";
case "01.00.00.00.00.00.FF.F1":
return "Power supply brownout detected below minimum required by node";
case "01.00.00.00.00.00.FF.F0":
return "Power supply brownout detected below minimum required by standard";
case "01.00.00.00.00.00.FE.00":
return "Ident button combination pressed";
case "01.00.00.00.00.00.FD.01":
return "Link error code 1 – the specific meaning is link wire protocol specific";
case "01.00.00.00.00.00.FD.02":
return "Link error code 2";
case "01.00.00.00.00.00.FD.03":
return "Link error code 3";
case "01.00.00.00.00.00.FD.04":
return "Link error code 4";

case "01.01.00.00.00.00.02.01":
return "Duplicate Node ID Detected";
case "01.01.00.00.00.00.03.03":
return "This node is a Train";
case "01.01.00.00.00.00.03.04":
return "This node is a Train Control Proxy";
case "01.01.00.00.00.00.06.01":
return "Firmware Corrupted";
case "01.01.00.00.00.00.06.02":
return "Firmware Upgrade Request by Hardware Switch";

default:
// check for fastclock and DCC ranges
if (eid.startsWith("01.01.00.00.01")) {
return fastClock();
} else if (eid.startsWith("01.01.02")) {
return dccRange();
} else {
return "Well-Known "+eid;
}
}
}

protected String fastClock() {
String clockNum = this.toShortString().substring(16, 17);
byte[] contents = this.getContents();
int lowByte = contents[7]&0xFF;
int highByte = contents[6]&0xFF;
int highByteMasked = 0x7F&highByte;
int bothBytes = highByte*256+lowByte;
String function = "";

String set = ((0x80 & highByte) == 0x80) ? "Set " : "";

if ((highByte & 0xF0) == 0xC0) { // set rate
int rate = (highByte&0xF)*256+lowByte;
function = "Set rate "+(rate/4.);
} else if (bothBytes == 0xF000) { //
function = "Query";
} else if (bothBytes == 0xF001) { //
function = "Stop";
} else if (bothBytes == 0xF002) { //
function = "Start";
} else if (bothBytes == 0xF003) { //
function = "Date Rollover";
} else if (highByteMasked < 24) { // time
String lowString = "00"+Integer.toString(lowByte);
lowString = lowString.substring(lowString.length()-2);
function = set+"time "+highByteMasked+":"+lowString;
} else if (highByteMasked <= 0x2C) { // date
String lowString = "00"+Integer.toString(lowByte);
lowString = lowString.substring(lowString.length()-2);
function = set+"date "+(highByteMasked-0x20)+"/"+lowString;
} else if (highByteMasked < 0x40) { // year
int year = (highByteMasked*256+lowByte)-0x3000;
function = set+"year "+year;
} else {
function = "reserved";
}

return "Fast Clock "+clockNum+" "+function;
}

protected String dccRange() {
String eid = this.toShortString();
if (eid.startsWith("01.01.02.00.00.FF")) {
return "DCC Acc Decoder "+parseAccDecoderNumber(this.toLong())+" active";

} else if (eid.startsWith("01.01.02.00.00.FE")) {
return "DCC Acc Decoder "+parseAccDecoderNumber(this.toLong())+" inactive";

} else if (eid.startsWith("01.01.02.00.00.FD")) {
return "DCC Turnout Feedback "+(this.toLong()&0x7FFL)+" active";

} else if (eid.startsWith("01.01.02.00.00.FC")) {
return "DCC Turnout Feedback "+(this.toLong()&0x7FFL)+" inactive";

} else if (eid.startsWith("01.01.02.00.00.FB")) {
return "DCC Sensor "+(this.toLong()&0xFFFL)+" active";

} else if (eid.startsWith("01.01.02.00.00.FA")) {
return "DCC Sensor "+(this.toLong()&0xFFFL)+" inactive";

} else if (eid.startsWith("01.01.02.00.01")) {
return "DCC Extended Accessory "
+((this.toLong()>>8)&0x7FFL)
+" "+(this.toLong()&0xFF);
} else {
return "DCC Well-Known "+this;
}
}

protected String parseAccDecoderNumber(long event) {
int input = (int)(event&0xFFF);

int result = (((input-8)>>1)+1)&0x7FF;

if ((event & 0x01) !=0 )
return ""+result+" N/C/On ";
else {
return ""+result+" R/T/Off";
}
}

protected String trainSearch() {
return "Train Search";
}

}
23 changes: 23 additions & 0 deletions src/org/openlcb/EventNameStore.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.openlcb;

/**
* Provide a mapping from EventID from/to User readable event names
*
* Intended to be implemented and provided externally to this library.
* The event names here obey some external syntax, and are sourced
* externally.
*
* This is deliberately separate from the
* {@link org.openlcb.implementations.EventTable}
* which is an internal structure specific to this library.
*
*
* @author Bob Jacobsen Copyright (C) 2024
*/
public interface EventNameStore {

public EventID getEventID(String eventName);

public String getEventName(EventID eventID);

}
3 changes: 2 additions & 1 deletion src/org/openlcb/ProducerConsumerEventReportMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public void applyTo(MessageDecoder decoder, Connection sender) {
/**
* Get the size of the payload, which doesn't include
* the eight bytes of the event ID itself
* @return payload size in bytes
*/
public int getPayloadSize() {
if (payload == null) return 0;
Expand Down Expand Up @@ -88,7 +89,7 @@ public byte[] getPayloadArray() {

@Override
public String toString() {
String retval = " Producer/Consumer Event Report "+eventID.toString();
String retval = super.toString() + " Producer/Consumer Event Report "+eventID.toString();

if ( getPayloadSize() > 0 ) {
retval = retval + " payload of "+getPayloadSize()+" : ";
Expand Down
2 changes: 2 additions & 0 deletions src/org/openlcb/Utilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ static public void HostToNetworkUint48(byte[] arr, int offset, long value) {
/**
* Find the longest starting substring of a List of Strings.
* This is useful for finding e.g. the common prefix of a replication dump
* @param list of Strings to compare
* @return longest leading substring
*/
@CheckReturnValue
@NonNull
Expand Down
2 changes: 2 additions & 0 deletions src/org/openlcb/can/AliasMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public void processFrame(OpenLcbCanFrame f) {
/**
* Store a local alias which should be kept when
* the caches are cleared by an AME global
* @param alias alias of the local node to preserve
* @param nid NodeID of the local alias to preserve
*/
public void insertLocalAlias(int alias, NodeID nid) {
localAliases.put(alias, nid);
Expand Down
1 change: 1 addition & 0 deletions src/org/openlcb/can/NIDaAlgorithm.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public int getNIDa() {
}

/**
* @param f frame to check
* @return True if frame matches current NodeID
*/
boolean compareDataAndNodeID(OpenLcbCanFrame f) {
Expand Down
2 changes: 2 additions & 0 deletions src/org/openlcb/cdi/CdiRep.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public static interface Map {
/**
* Add an item to the map. Useful if e.g. a non-mapped
* value is found in a location.
* @param key to be added
* @param entry to be added
*/
public void addItemToMap(String key, String entry);
}
Expand Down
4 changes: 2 additions & 2 deletions src/org/openlcb/cdi/cmd/BackupConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public static void writeConfigToFile(String fileName, ConfigRepresentation repr)
/**
* @param writer Receives output. Flushed at end, but not closed.
* @param repr Representation containing contents to be written.
* @throws IOException if trouble writing out
*/
public static void writeConfigToWriter(BufferedWriter writer, ConfigRepresentation repr) throws
IOException {
Expand All @@ -61,8 +62,7 @@ public void visitInt(ConfigRepresentation.IntegerEntry e) {

@Override
public void visitEvent(ConfigRepresentation.EventEntry e) {
writeEntry(finalWriter, e.key, Utilities.toHexDotsString(e.getValue
().getContents()));
writeEntry(finalWriter, e.key, e.getValue());
}
}
);
Expand Down
14 changes: 9 additions & 5 deletions src/org/openlcb/cdi/impl/ConfigRepresentation.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ public class ConfigRepresentation extends DefaultPropertyListenerSupport {
// Last time the progressbar was updated from the load.
private long lastProgress;


public org.openlcb.cdi.swing.CdiPanel.GuiItemFactory factory = null;

/**
* Connects to a node, populates the cache by fetching and parsing the CDI.
* @param connection OpenLCB network.
Expand Down Expand Up @@ -589,6 +590,7 @@ public boolean isHidden() {

/**
* Does this entry carry the readOnly hint?
* @return true if it carries the readOnly hint
*/
public boolean isReadOnlyConfigured() {
return group.isReadOnly();
Expand Down Expand Up @@ -734,19 +736,21 @@ public CdiRep.Item getCdiItem() {

@Override
protected void updateVisibleValue() {
EventID v = getValue();
String v = getValue();
if (v != null) {
lastVisibleValue = Utilities.toHexDotsString(v.getContents());
lastVisibleValue = v;
} else {
lastVisibleValue = "";
}
}

public EventID getValue() {
public String getValue() {
MemorySpaceCache cache = getCacheForSpace(space);
byte[] b = cache.read(origin, size);
if (b == null) return null;
return new EventID(b);
EventID eid = new EventID(b);
if (factory == null) return eid.toShortString();
return factory.getStringFromEventID(eid);
}

public void setValue(EventID event) {
Expand Down
Loading
Loading