org.bidib.wizard.simulation.IF2Simulator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bidibwizard-simulation Show documentation
Show all versions of bidibwizard-simulation Show documentation
jBiDiB BiDiB Wizard Simulation POM
The newest version!
package org.bidib.wizard.simulation;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.bidib.jbidibc.messages.AddressData;
import org.bidib.jbidibc.messages.BidibLibrary;
import org.bidib.jbidibc.messages.DccATidData;
import org.bidib.jbidibc.messages.DecoderIdAddressData;
import org.bidib.jbidibc.messages.DecoderUniqueIdData;
import org.bidib.jbidibc.messages.Feature;
import org.bidib.jbidibc.messages.StringData;
import org.bidib.jbidibc.messages.TidData;
import org.bidib.jbidibc.messages.enums.AddressTypeEnum;
import org.bidib.jbidibc.messages.enums.CommandStationPom;
import org.bidib.jbidibc.messages.enums.CommandStationProgState;
import org.bidib.jbidibc.messages.enums.CommandStationPt;
import org.bidib.jbidibc.messages.enums.CommandStationState;
import org.bidib.jbidibc.messages.enums.CsQueryTypeEnum;
import org.bidib.jbidibc.messages.enums.DccAOpCodeBm;
import org.bidib.jbidibc.messages.enums.DccAdvSelectInfoOpCode;
import org.bidib.jbidibc.messages.enums.FeatureEnum;
import org.bidib.jbidibc.messages.enums.RcPlusPhase;
import org.bidib.jbidibc.messages.enums.SpeedStepsEnum;
import org.bidib.jbidibc.messages.exception.ProtocolException;
import org.bidib.jbidibc.messages.message.BidibMessageInterface;
import org.bidib.jbidibc.messages.message.BidibRequestFactory;
import org.bidib.jbidibc.messages.message.CommandStationAccessoryAcknowledgeResponse;
import org.bidib.jbidibc.messages.message.CommandStationAccessoryMessage;
import org.bidib.jbidibc.messages.message.CommandStationBinaryStateMessage;
import org.bidib.jbidibc.messages.message.CommandStationDccAdvAcknowledgeResponse;
import org.bidib.jbidibc.messages.message.CommandStationDccAdvMessage;
import org.bidib.jbidibc.messages.message.CommandStationDriveAcknowledgeResponse;
import org.bidib.jbidibc.messages.message.CommandStationDriveMessage;
import org.bidib.jbidibc.messages.message.CommandStationDriveStateResponse;
import org.bidib.jbidibc.messages.message.CommandStationPomAcknowledgeResponse;
import org.bidib.jbidibc.messages.message.CommandStationPomMessage;
import org.bidib.jbidibc.messages.message.CommandStationProgMessage;
import org.bidib.jbidibc.messages.message.CommandStationProgStateResponse;
import org.bidib.jbidibc.messages.message.CommandStationQueryMessage;
import org.bidib.jbidibc.messages.message.CommandStationRcPlusAcknowledgeResponse;
import org.bidib.jbidibc.messages.message.CommandStationRcPlusMessage;
import org.bidib.jbidibc.messages.message.CommandStationSetStateMessage;
import org.bidib.jbidibc.messages.message.CommandStationStateResponse;
import org.bidib.jbidibc.messages.message.FeedbackCvResponse;
import org.bidib.jbidibc.messages.message.FeedbackDccAResponse;
import org.bidib.jbidibc.messages.message.StringResponse;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.bidib.jbidibc.simulation.InterfaceNode;
import org.bidib.jbidibc.simulation.SimulationBidibMessageProcessor;
import org.bidib.jbidibc.simulation.annotation.BidibNodeSimulator;
import org.bidib.jbidibc.simulation.nodes.DefaultNodeSimulator;
import org.bushe.swing.event.annotation.AnnotationProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@BidibNodeSimulator(vid = "13", pid = "132")
public class IF2Simulator extends DefaultNodeSimulator implements InterfaceNode {
private static final Logger LOGGER = LoggerFactory.getLogger(IF2Simulator.class);
private static final String SIMULATION_PANEL_CLASS =
"org.bidib.wizard.simulation.client.view.panel.GBMboostMasterPanel";
private CommandStationState commandStationState = CommandStationState.OFF;
private Map mapLocoCV = new LinkedHashMap();
private TidData tid = new TidData(new DecoderUniqueIdData(0x0D0C0B0A, 13), 1);
private DccATidData dccAdvTid = new DccATidData(0x0B0A, 1);
public IF2Simulator(byte[] nodeAddress, long uniqueId, boolean autoAddFeature,
SimulationBidibMessageProcessor messageReceiver, final BidibRequestFactory bidibRequestFactory) {
super(nodeAddress, uniqueId, autoAddFeature, messageReceiver, bidibRequestFactory);
// da000d840064ea --> 90000d840064ea
this.uniqueId = (uniqueId & 0x00FFFFFFFFFFFFL) | (0x90L << (12 * 4));
}
@Override
protected void prepareFeatures() {
super.prepareFeatures();
features.add(new Feature(BidibLibrary.FEATURE_GEN_SPYMODE, 1));
features.add(new Feature(BidibLibrary.FEATURE_GEN_WATCHDOG, 20));
features.add(new Feature(BidibLibrary.FEATURE_GEN_DRIVE_ACK, 1));
features.add(new Feature(BidibLibrary.FEATURE_GEN_SWITCH_ACK, 1));
features.add(new Feature(BidibLibrary.FEATURE_GEN_POM_REPEAT, 3));
features.add(new Feature(BidibLibrary.FEATURE_GEN_DRIVE_BUS, 0));
features.add(new Feature(BidibLibrary.FEATURE_GEN_LOK_LOST_DETECT, 1));
features.add(new Feature(BidibLibrary.FEATURE_GEN_NOTIFY_DRIVE_MANUAL, 1));
features.add(new Feature(BidibLibrary.FEATURE_GEN_EXT_AVAILABLE, 13));
// TODO enable this feature to send the debug string
// features.add(new Feature(BidibLibrary.FEATURE_STRING_DEBUG, 1));
}
@Override
protected void prepareCVs() {
super.prepareCVs();
}
@Override
public String getSimulationPanelClass() {
return SIMULATION_PANEL_CLASS;
}
@Override
public void start() {
LOGGER.info("Start the simulator for address: {}", getAddress());
AnnotationProcessor.process(this);
// setup loco decoder CV
mapLocoCV.put(1, Integer.valueOf(3));
mapLocoCV.put(29, Integer.valueOf(0));
mapLocoCV.put(28, Integer.valueOf(3)); // set the railcom config
super.start();
}
@Override
public void stop() {
AnnotationProcessor.unprocess(this);
super.stop();
}
@Override
protected byte[] prepareResponse(BidibMessageInterface bidibMessage) {
byte[] response = null;
switch (ByteUtils.getInt(bidibMessage.getType())) {
case BidibLibrary.MSG_CS_SET_STATE:
response = processCsSetStateRequest(bidibMessage);
break;
case BidibLibrary.MSG_CS_POM:
response = processCsPomRequest(bidibMessage);
break;
case BidibLibrary.MSG_CS_PROG:
response = processCsProgRequest(bidibMessage);
break;
case BidibLibrary.MSG_CS_DRIVE:
response = processCsDriveRequest(bidibMessage);
break;
case BidibLibrary.MSG_CS_ACCESSORY:
response = processCsAccessoryRequest(bidibMessage);
break;
case BidibLibrary.MSG_CS_RCPLUS:
response = processCsRcPlusRequest(bidibMessage);
break;
case BidibLibrary.MSG_CS_QUERY:
response = processCsQueryRequest(bidibMessage);
break;
case BidibLibrary.MSG_CS_BIN_STATE:
response = processCsBinStateRequest(bidibMessage);
break;
case BidibLibrary.MSG_CS_DCCA:
response = processCsDccAdvRequest(bidibMessage);
break;
default:
response = super.prepareResponse(bidibMessage);
break;
}
return response;
}
protected byte[] processCsSetStateRequest(BidibMessageInterface bidibMessage) {
LOGGER.info("Process the CsSetState request: {}", bidibMessage);
if (Feature.getIntFeatureValue(features, FeatureEnum.FEATURE_STRING_DEBUG.getNumber()) > 0) {
// 25.11.2019 21:05:40.051: [receiveQueueWorker] - << MSG_STRING[[0],num=17,type=149,data=[1, 3, 16, 66,
// 105, 68, 105, 66, 32, 68, 101, 99, 111, 100, 101, 114, 32, 45, 32]] : 16 00 11 95 01 03 10 42 69 44 69 42
// 20 44 65 63 6F 64 65 72 20 2D 20
// 25.11.2019 21:05:40.053: [receiveQueueWorker] - << MSG_STRING[[0],num=18,type=149,data=[1, 3, 6, 48, 46,
// 50, 46, 48, 10]] : 0C 00 12 95 01 03 06 30 2E 32 2E 30 0A
try {
StringResponse stringResponse =
new StringResponse(bidibMessage.getAddr(), getNextSendNum(), (byte) StringData.NAMESPACE_DEBUG,
(byte) 3, new byte[] { 0x10, 0x42, 0x69, 0x44, 0x69, 0x42, 0x20, 0x44, 0x65, 0x63, 0x6F, 0x64,
0x65, 0x72, 0x20, 0x2D, 0x20 });
sendSpontanousResponse(stringResponse.getContent());
StringResponse stringResponse2 =
new StringResponse(bidibMessage.getAddr(), getNextSendNum(), (byte) StringData.NAMESPACE_DEBUG,
(byte) 3, new byte[] { 0x06, 0x30, 0x2E, 0x32, 0x2E, 0x30, 0x0A });
sendSpontanousResponse(stringResponse2.getContent());
// 01 04 11 53 30 36 30 37 30 30 33 46 34 43 31 32 30 33 0A 0D
StringResponse stringResponse3 =
new StringResponse(bidibMessage.getAddr(), getNextSendNum(), (byte) StringData.NAMESPACE_DEBUG,
(byte) 4, new byte[] { 0x11, 0x53, 0x30, 0x36, 0x30, 0x37, 0x30, 0x30, 0x33, 0x46, 0x34, 0x43,
0x31, 0x32, 0x30, 0x33, 0x0A, 0x0D });
sendSpontanousResponse(stringResponse3.getContent());
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationState response failed.", ex);
}
}
byte[] response = null;
try {
CommandStationSetStateMessage commandStationSetStateMessage = (CommandStationSetStateMessage) bidibMessage;
CommandStationState state = commandStationSetStateMessage.getState();
LOGGER.info("The requested command station state is: {}", state);
switch (state) {
case OFF:
commandStationState = CommandStationState.OFF;
break;
case STOP:
case SOFTSTOP:
commandStationState = CommandStationState.STOP;
break;
case GO:
case GO_IGN_WD:
commandStationState = CommandStationState.GO;
break;
case PROG:
commandStationState = CommandStationState.PROG;
break;
case QUERY:
LOGGER.info("Query command station state requested, return the current command station state!");
break;
default:
LOGGER.warn("Unprocessed command station state: {}", state);
break;
}
LOGGER.info("Return current command station state: {}", commandStationState);
CommandStationStateResponse commandStationStateResponse =
new CommandStationStateResponse(bidibMessage.getAddr(), getNextSendNum(),
commandStationState.getType());
response = commandStationStateResponse.getContent();
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationState response failed.", ex);
}
return response;
}
protected byte[] processCsPomRequest(BidibMessageInterface bidibMessage) {
LOGGER.info("Process the CsPom request: {}", bidibMessage);
byte[] response = null;
// prepare the POM acknowledge
try {
CommandStationPomMessage commandStationPomMessage = (CommandStationPomMessage) bidibMessage;
org.bidib.jbidibc.messages.PomAddressData addressData = commandStationPomMessage.getDecoderAddress();
LOGGER.info("Received addressData: {}", addressData);
CommandStationPomAcknowledgeResponse commandStationPomAckResponse =
new CommandStationPomAcknowledgeResponse(bidibMessage.getAddr(), getNextSendNum(), addressData,
(byte) 1);
response = commandStationPomAckResponse.getContent();
LOGGER.info("Publish the running response: {}", commandStationPomAckResponse);
publishResponse(response);
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationPomAck response failed.", ex);
}
// prepare the MSG_BM_CV that contains the real data
try {
LOGGER.info("prepare the MSG_BM_CV that contains the real data.");
CommandStationPomMessage commandStationPomMessage = (CommandStationPomMessage) bidibMessage;
org.bidib.jbidibc.messages.PomAddressData addressData = commandStationPomMessage.getDecoderAddress();
int cvNumber = commandStationPomMessage.getCvNumber();
LOGGER.info("Current CV number: {}", cvNumber);
byte cvValue = 12;
if (cvNumber == 29) {
cvValue = 0;
}
CommandStationPom opCode =
CommandStationPom.valueOf(ByteUtils.getLowByte(commandStationPomMessage.getOpCode()));
switch (opCode) {
case WR_BYTE:
cvValue = ByteUtils.getLowByte(commandStationPomMessage.getCvValue());
break;
default:
break;
}
FeedbackCvResponse feedbackCvResponse =
new FeedbackCvResponse(bidibMessage.getAddr(), getNextSendNum(), addressData.getAddress(), cvNumber - 1,
cvValue);
response = feedbackCvResponse.getContent();
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationPomAck response failed.", ex);
}
return response;
}
protected byte[] processCsProgRequest(BidibMessageInterface bidibMessage) {
LOGGER.info("Process the CsProg request: {}", bidibMessage);
byte[] response = null;
try {
CommandStationProgMessage commandStationProgMessage = (CommandStationProgMessage) bidibMessage;
CommandStationPt opCode = commandStationProgMessage.getOpCode();
int cvNumber = commandStationProgMessage.getCvNumber();
int cvData = commandStationProgMessage.getCvData();
LOGGER.info("Received opCode: {}, cvNumber: {}, cvData: {}", opCode, cvNumber, cvData);
boolean sendTimeoutResponse = false;
switch (opCode) {
case BIDIB_CS_PROG_BREAK:
break;
case BIDIB_CS_PROG_QUERY:
break;
case BIDIB_CS_PROG_RDWR_BIT:
if ((cvData & 0x10) == 0x10) {
Integer storedValue = mapLocoCV.get(cvNumber);
// write operation
if (storedValue != null) {
byte byteValue = ByteUtils.getLowByte(storedValue.intValue());
byteValue =
ByteUtils.setBit(byteValue, (cvData & 0x08) == 0x08 ? true : false, cvData & 0x07);
LOGGER.info("Changed CV value: {}", ByteUtils.byteToHex(byteValue));
mapLocoCV.put(cvNumber, Integer.valueOf(byteValue));
}
else {
byte byteValue = 0;
byteValue =
ByteUtils.setBit(byteValue, (cvData & 0x08) == 0x08 ? true : false, cvData & 0x07);
LOGGER.info("Changed CV value: {}", ByteUtils.byteToHex(byteValue));
mapLocoCV.put(cvNumber, Integer.valueOf(byteValue));
}
}
else {
// read operation
Integer storedValue = mapLocoCV.get(cvNumber);
if (storedValue != null) {
byte byteValue = ByteUtils.getLowByte(storedValue.intValue());
boolean bitIsSetEqual =
ByteUtils.isBitSetEqual(byteValue, ByteUtils.getBit(cvData, 3), cvData & 0x07);
LOGGER.info("Verify bitIsSetEqual: {}, byteValue: {}", bitIsSetEqual, byteValue);
if (!bitIsSetEqual) {
LOGGER.warn("Send timeout response!");
sendTimeoutResponse = true;
}
}
else {
LOGGER.warn("The requested CV value is not stored, cvNumber: {}", cvNumber);
sendTimeoutResponse = true;
}
}
break;
case BIDIB_CS_PROG_WR_BYTE:
mapLocoCV.put(cvNumber, cvData);
break;
default:
Integer storedValue = mapLocoCV.get(cvNumber);
if (storedValue != null) {
cvData = ByteUtils.getLowByte(storedValue.intValue());
}
else {
LOGGER.warn("The requested CV value is not stored, cvNumber: {}", cvNumber);
sendTimeoutResponse = true;
}
break;
}
CommandStationProgStateResponse commandStationProgStateResponse =
new CommandStationProgStateResponse(bidibMessage.getAddr(), getNextSendNum(),
CommandStationProgState.PROG_RUNNING, 1, cvNumber, cvData);
response = commandStationProgStateResponse.getContent();
LOGGER.info("Publish the running response: {}", commandStationProgStateResponse);
publishResponse(response);
LOGGER.info("Sleep a second.");
// sleep some time
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
LOGGER.warn("Sleep thread was interrupted.", e);
}
if (!sendTimeoutResponse) {
LOGGER.info("Prepare the OKAY state response.");
commandStationProgStateResponse =
new CommandStationProgStateResponse(bidibMessage.getAddr(), getNextSendNum(),
CommandStationProgState.PROG_OKAY, 1, cvNumber, cvData);
}
else {
LOGGER.info("Prepare the NO_ANSWER state response.");
commandStationProgStateResponse =
new CommandStationProgStateResponse(bidibMessage.getAddr(), getNextSendNum(),
CommandStationProgState.PROG_NO_ANSWER, 1, cvNumber, 0xFF);
}
response = commandStationProgStateResponse.getContent();
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationProgState response failed.", ex);
}
return response;
}
protected byte[] processCsDriveRequest(BidibMessageInterface bidibMessage) {
LOGGER.info("Process the CsDrive request: {}", bidibMessage);
byte[] response = null;
try {
CommandStationDriveMessage commandStationDriveMessage = (CommandStationDriveMessage) bidibMessage;
org.bidib.jbidibc.messages.AddressData addressData = commandStationDriveMessage.getDecoderAddress();
int messageNumber = commandStationDriveMessage.getNum();
LOGGER.info("Received addressData: {}", addressData);
CommandStationDriveAcknowledgeResponse commandStationDriveAckResponse =
new CommandStationDriveAcknowledgeResponse(bidibMessage.getAddr(), getNextSendNum(), addressData,
(byte) 1, Integer.valueOf(messageNumber));
response = commandStationDriveAckResponse.getContent();
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationDriveAck response failed.", ex);
}
return response;
}
private byte[] processCsBinStateRequest(BidibMessageInterface bidibMessage) {
LOGGER.info("Process the CsBinState request: {}", bidibMessage);
byte[] response = null;
try {
CommandStationBinaryStateMessage commandStationBinStateMessage =
(CommandStationBinaryStateMessage) bidibMessage;
org.bidib.jbidibc.messages.AddressData addressData = commandStationBinStateMessage.getDecoderAddress();
int binStateNumber = commandStationBinStateMessage.getBinaryStateNumber();
int binStateValue = commandStationBinStateMessage.getBinaryStateValue();
int messageNumber = commandStationBinStateMessage.getNum();
LOGGER
.info("Received addressData: {}, binStateNumber: {}, binStateValue: {}", addressData, binStateNumber,
binStateValue);
CommandStationDriveAcknowledgeResponse commandStationDriveAckResponse =
new CommandStationDriveAcknowledgeResponse(bidibMessage.getAddr(), getNextSendNum(), addressData,
(byte) 1, Integer.valueOf(messageNumber));
response = commandStationDriveAckResponse.getContent();
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationDriveAck response failed.", ex);
}
return response;
}
protected byte[] processCsQueryRequest(BidibMessageInterface bidibMessage) {
LOGGER.info("Process the CsQuery request: {}", bidibMessage);
byte[] response = null;
try {
CommandStationQueryMessage commandStationQueryMessage = (CommandStationQueryMessage) bidibMessage;
CsQueryTypeEnum csQueryType = commandStationQueryMessage.getCsQueryType();
switch (csQueryType) {
case LOCO_LIST:
// prepare some locos
// TODO check the real csQuery value to check if a single loco is requested
org.bidib.jbidibc.messages.AddressData addressData =
new AddressData(13, AddressTypeEnum.LOCOMOTIVE_FORWARD);
byte[] functions = new byte[] { (byte) 0x80, 0x00, 0x72, (byte) 0x85 };
CommandStationDriveStateResponse driveStateResponse =
new CommandStationDriveStateResponse(bidibMessage.getAddr(), getNextSendNum(), 0x41,
addressData, SpeedStepsEnum.DCC128, 39, functions);
response = driveStateResponse.getContent();
break;
default:
LOGGER.warn("The CsQueryRequest is not implemented for type: {}", csQueryType);
break;
}
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationDriveAck response failed.", ex);
}
return response;
}
protected byte[] processCsAccessoryRequest(BidibMessageInterface bidibMessage) {
LOGGER.info("Process the CsAccessory request: {}", bidibMessage);
byte[] response = null;
try {
CommandStationAccessoryMessage commandStationAccessoryMessage =
(CommandStationAccessoryMessage) bidibMessage;
org.bidib.jbidibc.messages.AddressData addressData = commandStationAccessoryMessage.getDecoderAddress();
LOGGER.info("Received addressData: {}", addressData);
CommandStationAccessoryAcknowledgeResponse commandStationAccessoryAckResponse =
new CommandStationAccessoryAcknowledgeResponse(bidibMessage.getAddr(), getNextSendNum(), addressData,
(byte) 1);
response = commandStationAccessoryAckResponse.getContent();
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationAccessoryAck response failed.", ex);
}
return response;
}
private static class DccAdvDecoderInfo {
private DecoderUniqueIdData did;
private String fullName;
private String shortName;
private byte[] firmwareId;
private String productName;
private int lastFullNameIndex;
private int selectedNamespace;
private int retryCounter;
private int logonAssignCounter;
public DccAdvDecoderInfo(long mun, int mid, String fullName, String shortName, byte[] firmwareId,
String productName) {
did = new DecoderUniqueIdData(mun, mid);
this.fullName = fullName;
this.shortName = shortName;
this.firmwareId = firmwareId;
this.productName = productName;
}
public int getLastFullNameIndex() {
return lastFullNameIndex;
}
public void setLastFullNameIndex(int lastFullNameIndex) {
this.lastFullNameIndex = lastFullNameIndex;
}
public void setSelectedNamespace(int selectedNamespace) {
LOGGER.info("Set the selected namespace of the decoder: {}", selectedNamespace);
this.selectedNamespace = selectedNamespace;
}
public int getSelectedNamespace() {
return selectedNamespace;
}
public int getRetryCounter() {
return retryCounter;
}
public void setRetryCounter(int retryCounter) {
this.retryCounter = retryCounter;
}
public void incRetryCounter() {
this.retryCounter++;
}
}
private List dccAdvDecoders = new LinkedList<>();
private DccAdvDecoderInfo activeDccAdvDecoder;
protected byte[] processCsDccAdvRequest(BidibMessageInterface bidibMessage) {
LOGGER.info("Process the DccAdv request: {}", bidibMessage);
byte[] response = null;
// prepare the DCCAdv acknowledge
try {
CommandStationDccAdvMessage commandStationDccAdvMessage = (CommandStationDccAdvMessage) bidibMessage;
CommandStationDccAdvAcknowledgeResponse acknowledgeResponse = null;
switch (commandStationDccAdvMessage.getOpCode()) {
case BIDIB_DCCA_GET_TID:
acknowledgeResponse =
new CommandStationDccAdvAcknowledgeResponse(bidibMessage.getAddr(), getNextSendNum(),
dccAdvTid);
break;
case BIDIB_DCCA_LOGON_ENABLE_ALL:
LOGGER.info("Enable all was received.");
if (CollectionUtils.isEmpty(dccAdvDecoders)) {
LOGGER.info("Prepare the dccAdvDecoders.");
int mid = 0x0D;
for (long index = 1; index < 5; index++) {
long mun = 0x04030200L + index;
DccAdvDecoderInfo decoder =
new DccAdvDecoderInfo(mun, mid, "BiDiB Loco Decoder ..: " + index, "Shrtna_" + index,
new byte[] { 0x00, 0x00, (byte) 0xFB, 0x02, 0x00, 0x02, 0x00, 0x01 }, "TamsFDR");
dccAdvDecoders.add(decoder);
}
}
for (DccAdvDecoderInfo decoder : dccAdvDecoders) {
DecoderIdAddressData addressData =
new DecoderIdAddressData(decoder.did.getMun(), decoder.did.getMid());
LOGGER.info("Return demo decoder with addressData: {}", addressData);
int detectorAddress = 0;
FeedbackDccAResponse feedbackResponse =
new FeedbackDccAResponse(bidibMessage.getAddr(), getNextSendNum(), detectorAddress,
DccAOpCodeBm.BIDIB_DCCA_LOGON_NEW_DID, addressData);
publishResponse(feedbackResponse.getContent());
}
break;
case BIDIB_DCCA_LOGON_ASSIGN:
LOGGER.info("Address is assigned: {}", commandStationDccAdvMessage.getAssignedAddress());
int detectorAddress = 0;
int hashValue = commandStationDccAdvMessage.getAssignedAddress();
DecoderUniqueIdData did = commandStationDccAdvMessage.getDid();
// search the decoder
DccAdvDecoderInfo decoder = findDecoder(did);
decoder.logonAssignCounter++;
if (decoder != null && decoder.logonAssignCounter < 3 && (decoder.did.getMun() % 2 == 0)) {
LOGGER.warn("Ignore LogonAssign request, decoder: {}", decoder);
break;
}
LOGGER.info("Provide the hashValue: {}, did: {}", hashValue, did);
// send the assign ack
FeedbackDccAResponse feedbackResponse =
new FeedbackDccAResponse(bidibMessage.getAddr(), getNextSendNum(), detectorAddress,
DccAOpCodeBm.BIDIB_DCCA_LOGON_ASSIGN_ACK, did, hashValue);
publishResponse(feedbackResponse.getContent());
break;
case BIDIB_DCCA_SELECT_INFO:
LOGGER.info("GetInfo is requested.");
DecoderUniqueIdData didGetInfo = commandStationDccAdvMessage.getDid();
DccAdvSelectInfoOpCode getInfoOpCode = commandStationDccAdvMessage.getInfoOpCode();
LOGGER.info("Provided did: {}, getInfoOpCode: {}", didGetInfo, getInfoOpCode);
decoder = findDecoder(didGetInfo);
LOGGER.info("Found registered decoder: {}", decoder);
detectorAddress = 0;
// keep the active decoder
activeDccAdvDecoder = decoder;
activeDccAdvDecoder.setSelectedNamespace(ByteUtils.getInt(getInfoOpCode.getType()));
switch (getInfoOpCode) {
case BIDIB_DCCA_SPACE_SHORTINFO:
break;
case BIDIB_DCCA_SPACE_SHORTGUI:
break;
case BIDIB_DCCA_SPACE_FIRMWARE_ID:
activeDccAdvDecoder.setLastFullNameIndex(0);
break;
case BIDIB_DCCA_SPACE_PRODUCTNAME:
activeDccAdvDecoder.setLastFullNameIndex(0);
break;
case BIDIB_DCCA_SPACE_SHORTNAME:
activeDccAdvDecoder.setLastFullNameIndex(0);
break;
case BIDIB_DCCA_SPACE_FULLNAME:
activeDccAdvDecoder.setLastFullNameIndex(0);
break;
default:
LOGGER.warn("Unknown getInfoOpCode: {}", getInfoOpCode);
break;
}
break;
case BIDIB_DCCA_GET_DATA:
LOGGER.info("GetInfo_Cont is requested.");
int repetitions = commandStationDccAdvMessage.getRepetitions();
detectorAddress = 0;
if (activeDccAdvDecoder != null) {
FeedbackDccAResponse feedbackResponseInfo = null;
LOGGER
.info("Get the data from the selected namespace: {}, repetitions: {}",
activeDccAdvDecoder.getSelectedNamespace(), repetitions);
switch (activeDccAdvDecoder.getSelectedNamespace()) {
case BidibLibrary.BIDIB_DCCA_SELECT_INFO_SHORTINFO:
feedbackResponseInfo =
new FeedbackDccAResponse(bidibMessage.getAddr(), getNextSendNum(), detectorAddress,
DccAOpCodeBm.BIDIB_DCCA_INFO_SHORTINFO, activeDccAdvDecoder.did, 0 /* index */,
new byte[] { 0x46, (byte) 0xA5, 0x18, 0x00, 0x00 });
publishResponse(feedbackResponseInfo.getContent());
break;
case BidibLibrary.BIDIB_DCCA_SELECT_INFO_SHORTGUI:
feedbackResponseInfo =
new FeedbackDccAResponse(bidibMessage.getAddr(), getNextSendNum(), detectorAddress,
DccAOpCodeBm.BIDIB_DCCA_INFO_SHORTGUI, activeDccAdvDecoder.did, 0 /* index */,
new byte[] { (byte) 0x01 /* 0x91 */, 0x00, 0x00, 0x00, 0x00 });
publishResponse(feedbackResponseInfo.getContent());
break;
case BidibLibrary.BIDIB_DCCA_SELECT_INFO_FIRMWARE_ID:
int lastFirmwareIdIndex = activeDccAdvDecoder.getLastFullNameIndex();
// firmware id, size = 8 bytes
for (int idx = 0; idx < repetitions; idx++) {
activeDccAdvDecoder.setLastFullNameIndex(lastFirmwareIdIndex);
int startIndex = lastFirmwareIdIndex * 4;
LOGGER
.info("startIndex: {}", startIndex,
ByteUtils.bytesToHex(activeDccAdvDecoder.firmwareId));
byte[] firmwareIdPart =
ByteUtils.subArray(activeDccAdvDecoder.firmwareId, startIndex, 4);
LOGGER
.info("Provide the firmwareIdPart: {}, lastFullNameIndex: {}, startIndex: {}",
ByteUtils.bytesToHex(firmwareIdPart), lastFirmwareIdIndex, startIndex);
if (idx == 0 && activeDccAdvDecoder.getRetryCounter() == 0) {
LOGGER.warn("Skip send the part of the firmware id: {}", firmwareIdPart);
}
else {
feedbackResponseInfo =
new FeedbackDccAResponse(bidibMessage.getAddr(), getNextSendNum(),
detectorAddress, DccAOpCodeBm.BIDIB_DCCA_INFO_FIRMWAREID,
activeDccAdvDecoder.did, lastFirmwareIdIndex, firmwareIdPart);
}
if (feedbackResponseInfo != null) {
publishResponse(feedbackResponseInfo.getContent());
}
lastFirmwareIdIndex++;
feedbackResponseInfo = null;
}
activeDccAdvDecoder.incRetryCounter();
break;
case BidibLibrary.BIDIB_DCCA_SELECT_INFO_PRODUCTNAME:
int lastProductNameIndex = activeDccAdvDecoder.getLastFullNameIndex();
// productName, size = 8 bytes
for (int idx = 0; idx < repetitions; idx++) {
activeDccAdvDecoder.setLastFullNameIndex(lastProductNameIndex);
int startIndex = lastProductNameIndex * 4;
String productNamePart =
StringUtils
.substring(activeDccAdvDecoder.productName, startIndex, startIndex + 4);
LOGGER
.info("Provide the productNamePart: {}, lastFullNameIndex: {}, startIndex: {}",
productNamePart, lastProductNameIndex, startIndex);
if (idx == 0 && activeDccAdvDecoder.getRetryCounter() == 1) {
LOGGER.warn("Skip send the part of the productName: {}", productNamePart);
}
else {
feedbackResponseInfo =
new FeedbackDccAResponse(bidibMessage.getAddr(), getNextSendNum(),
detectorAddress, DccAOpCodeBm.BIDIB_DCCA_INFO_PRODUCTNAME,
activeDccAdvDecoder.did, lastProductNameIndex,
productNamePart.getBytes(StandardCharsets.ISO_8859_1));
}
if (feedbackResponseInfo != null) {
publishResponse(feedbackResponseInfo.getContent());
}
lastProductNameIndex++;
feedbackResponseInfo = null;
activeDccAdvDecoder.incRetryCounter();
}
break;
case BidibLibrary.BIDIB_DCCA_SELECT_INFO_SHORTNAME:
int lastShortNameIndex = activeDccAdvDecoder.getLastFullNameIndex();
// shortName, size = 8 bytes
for (int idx = 0; idx < repetitions; idx++) {
activeDccAdvDecoder.setLastFullNameIndex(lastShortNameIndex);
int startIndex = lastShortNameIndex * 4;
String shortNamePart =
StringUtils
.substring(activeDccAdvDecoder.shortName, startIndex, startIndex + 4);
LOGGER
.info("Provide the shortNamePart: {}, lastFullNameIndex: {}, startIndex: {}",
shortNamePart, lastShortNameIndex, startIndex);
feedbackResponseInfo =
new FeedbackDccAResponse(bidibMessage.getAddr(), getNextSendNum(),
detectorAddress, DccAOpCodeBm.BIDIB_DCCA_INFO_SHORTNAME,
activeDccAdvDecoder.did, lastShortNameIndex,
shortNamePart.getBytes(StandardCharsets.ISO_8859_1));
if (feedbackResponseInfo != null) {
publishResponse(feedbackResponseInfo.getContent());
}
lastShortNameIndex++;
}
break;
case BidibLibrary.BIDIB_DCCA_SELECT_INFO_FULLNAME:
int lastFullNameIndex = activeDccAdvDecoder.getLastFullNameIndex();
// fullName, size = 24 bytes
for (int idx = 0; idx < repetitions; idx++) {
activeDccAdvDecoder.setLastFullNameIndex(lastFullNameIndex);
int startIndex = lastFullNameIndex * 4;
String fullNamePart =
StringUtils.substring(activeDccAdvDecoder.fullName, startIndex, startIndex + 4);
LOGGER
.info("Provide the fullNamePart: {}, lastFullNameIndex: {}, startIndex: {}",
fullNamePart, lastFullNameIndex, startIndex);
feedbackResponseInfo =
new FeedbackDccAResponse(bidibMessage.getAddr(), getNextSendNum(),
detectorAddress, DccAOpCodeBm.BIDIB_DCCA_INFO_FULLNAME,
activeDccAdvDecoder.did, lastFullNameIndex,
fullNamePart.getBytes(StandardCharsets.ISO_8859_1));
if (feedbackResponseInfo != null) {
publishResponse(feedbackResponseInfo.getContent());
}
lastFullNameIndex++;
}
break;
}
activeDccAdvDecoder = null;
}
break;
default:
LOGGER
.error("The DccAdv acknowledge is not yet implemented for OpCode: {}",
commandStationDccAdvMessage.getOpCode());
break;
}
if (acknowledgeResponse != null) {
response = acknowledgeResponse.getContent();
}
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationDccAdvAck response failed.", ex);
}
return response;
}
private DccAdvDecoderInfo findDecoder(final DecoderUniqueIdData did) {
DccAdvDecoderInfo decoder = IterableUtils.find(dccAdvDecoders, new Predicate() {
@Override
public boolean evaluate(DccAdvDecoderInfo decoder) {
if (Objects.equals(decoder.did, did)) {
return true;
}
return false;
}
});
return decoder;
}
protected byte[] processCsRcPlusRequest(BidibMessageInterface bidibMessage) {
LOGGER.info("Process the CsRcPlus request: {}", bidibMessage);
byte[] response = null;
// prepare the RCPLUS acknowledge
try {
CommandStationRcPlusMessage commandStationRcPlusMessage = (CommandStationRcPlusMessage) bidibMessage;
CommandStationRcPlusAcknowledgeResponse acknowledgeResponse = null;
switch (commandStationRcPlusMessage.getOpCode()) {
case RC_GET_TID:
acknowledgeResponse =
new CommandStationRcPlusAcknowledgeResponse(bidibMessage.getAddr(), getNextSendNum(), tid);
response = acknowledgeResponse.getContent();
break;
case RC_SET_TID:
TidData newTid = commandStationRcPlusMessage.getTid();
LOGGER.info("Set the new TID: {}", newTid);
tid = newTid;
acknowledgeResponse =
new CommandStationRcPlusAcknowledgeResponse(bidibMessage.getAddr(), getNextSendNum(), tid);
response = acknowledgeResponse.getContent();
break;
case RC_PING_ONCE_P0:
acknowledgeResponse =
new CommandStationRcPlusAcknowledgeResponse(bidibMessage.getAddr(), getNextSendNum(),
RcPlusPhase.P0, 0x00);
response = acknowledgeResponse.getContent();
break;
case RC_PING_ONCE_P1:
acknowledgeResponse =
new CommandStationRcPlusAcknowledgeResponse(bidibMessage.getAddr(), getNextSendNum(),
RcPlusPhase.P1, 0x00);
response = acknowledgeResponse.getContent();
break;
default:
LOGGER
.error("The RailCom+ acknowledge is not yet implemented for OpCode: {}",
commandStationRcPlusMessage.getOpCode());
break;
}
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationRcPlusAck response failed.", ex);
}
return response;
}
@Override
protected void processResetRequest(BidibMessageInterface bidibMessage) {
LOGGER.info("Process the reset request, bidibMessage: {}", bidibMessage);
resetSendNum();
// notify the master that we're gone
// EventBus.publish(new NodeLostEvent(nodeAddress[nodeAddress.length - 1]));
}
}