
org.bidib.wizard.simulation.GBMboostMasterSimulator Maven / Gradle / Ivy
package org.bidib.wizard.simulation;
import java.util.LinkedHashMap;
import java.util.Map;
import org.bidib.jbidibc.core.BidibLibrary;
import org.bidib.jbidibc.core.Feature;
import org.bidib.jbidibc.core.RcPlusUniqueIdData;
import org.bidib.jbidibc.core.TidData;
import org.bidib.jbidibc.core.enumeration.CommandStationProgState;
import org.bidib.jbidibc.core.enumeration.CommandStationPt;
import org.bidib.jbidibc.core.enumeration.CommandStationState;
import org.bidib.jbidibc.core.enumeration.RcPlusPhase;
import org.bidib.jbidibc.core.exception.ProtocolException;
import org.bidib.jbidibc.core.message.BidibCommand;
import org.bidib.jbidibc.core.message.CommandStationAccessoryAcknowledgeResponse;
import org.bidib.jbidibc.core.message.CommandStationAccessoryMessage;
import org.bidib.jbidibc.core.message.CommandStationDriveAcknowledgeResponse;
import org.bidib.jbidibc.core.message.CommandStationDriveMessage;
import org.bidib.jbidibc.core.message.CommandStationPomAcknowledgeResponse;
import org.bidib.jbidibc.core.message.CommandStationPomMessage;
import org.bidib.jbidibc.core.message.CommandStationProgMessage;
import org.bidib.jbidibc.core.message.CommandStationProgStateResponse;
import org.bidib.jbidibc.core.message.CommandStationRcPlusAcknowledgeResponse;
import org.bidib.jbidibc.core.message.CommandStationRcPlusMessage;
import org.bidib.jbidibc.core.message.CommandStationSetStateMessage;
import org.bidib.jbidibc.core.message.CommandStationStateResponse;
import org.bidib.jbidibc.core.message.FeedbackCvResponse;
import org.bidib.jbidibc.core.message.NodeLostResponse;
import org.bidib.jbidibc.core.message.NodeNewResponse;
import org.bidib.jbidibc.core.message.NodeTabCountResponse;
import org.bidib.jbidibc.core.message.NodeTabResponse;
import org.bidib.jbidibc.core.utils.ByteUtils;
import org.bidib.jbidibc.core.utils.NodeUtils;
import org.bidib.jbidibc.simulation.InterfaceNode;
import org.bidib.jbidibc.simulation.SimulatorNode;
import org.bidib.jbidibc.simulation.SimulatorRegistry;
import org.bidib.jbidibc.simulation.events.NodeAvailableEvent;
import org.bidib.jbidibc.simulation.events.NodeLostEvent;
import org.bidib.jbidibc.simulation.net.SimulationBidibMessageProcessor;
import org.bushe.swing.event.annotation.EventSubscriber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GBMboostMasterSimulator extends GBMboostNodeSimulator implements InterfaceNode {
private static final Logger LOGGER = LoggerFactory.getLogger(GBMboostMasterSimulator.class);
private static final String SIMULATION_PANEL_CLASS =
"org.bidib.wizard.mvc.simulation.view.panel.GBMboostMasterPanel";
private byte localAddrIndex;
private CommandStationState commandStationState = CommandStationState.OFF;
private Map mapLocoCV = new LinkedHashMap();
private TidData tid = new TidData(new RcPlusUniqueIdData(0x0D0C0B0A, 13), 1);
public GBMboostMasterSimulator(byte[] nodeAddress, long uniqueId, boolean autoAddFeature,
SimulationBidibMessageProcessor messageReceiver) {
super(nodeAddress, uniqueId, autoAddFeature, messageReceiver);
}
@Override
protected void prepareFeatures() {
super.prepareFeatures();
features.add(new Feature(BidibLibrary.FEATURE_GEN_SPYMODE, 1));
features.add(new Feature(BidibLibrary.FEATURE_GEN_WATCHDOG, 1));
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, 1));
features.add(new Feature(BidibLibrary.FEATURE_GEN_DRIVE_BUS, 1));
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_RCPLUS_AVAILABLE, 1));
// remove FW udpate feature
features.remove(new Feature(BidibLibrary.FEATURE_FW_UPDATE_MODE, 1));
}
@Override
public String getSimulationPanelClass() {
return SIMULATION_PANEL_CLASS;
}
/**
* @return the subNodes
*/
public Map getSubNodes() {
return subNodes;
}
/**
* Add a new subnode.
*
* @param simulator
* the simulator
*/
@Override
public void addSubNode(SimulatorNode simulator) {
String nodeAddress = simulator.getLocalAddress().trim();
// we must store the node under the local address
LOGGER.info("Add new subnode, address: {}, simulator: {}", nodeAddress, simulator);
subNodes.put(nodeAddress, simulator);
}
@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(BidibCommand 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;
default:
response = super.prepareResponse(bidibMessage);
break;
}
return response;
}
protected byte[] processCsSetStateRequest(BidibCommand bidibMessage) {
LOGGER.info("Process the CsSetState request: {}", bidibMessage);
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;
default:
break;
}
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(BidibCommand bidibMessage) {
LOGGER.info("Process the CsPom request: {}", bidibMessage);
byte[] response = null;
// prepare the POM acknowledge
try {
CommandStationPomMessage commandStationPomMessage = (CommandStationPomMessage) bidibMessage;
org.bidib.jbidibc.core.AddressData 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.core.AddressData addressData = commandStationPomMessage.getDecoderAddress();
int cvNumber = commandStationPomMessage.getCvNumber();
byte cvValue = 12;
FeedbackCvResponse feedbackCvResponse =
new FeedbackCvResponse(bidibMessage.getAddr(), getNextSendNum(), addressData.getAddress(), cvNumber,
cvValue);
response = feedbackCvResponse.getContent();
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationPomAck response failed.", ex);
}
return response;
}
protected byte[] processCsProgRequest(BidibCommand 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 + 1);
// 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 + 1, 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 + 1, Integer.valueOf(byteValue));
}
}
else {
// read operation
Integer storedValue = mapLocoCV.get(cvNumber + 1);
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 + 1, cvData);
break;
default:
Integer storedValue = mapLocoCV.get(cvNumber + 1);
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(BidibCommand bidibMessage) {
LOGGER.info("Process the CsDrive request: {}", bidibMessage);
byte[] response = null;
try {
CommandStationDriveMessage commandStationDriveMessage = (CommandStationDriveMessage) bidibMessage;
org.bidib.jbidibc.core.AddressData addressData = commandStationDriveMessage.getDecoderAddress();
LOGGER.info("Received addressData: {}", addressData);
CommandStationDriveAcknowledgeResponse commandStationDriveAckResponse =
new CommandStationDriveAcknowledgeResponse(bidibMessage.getAddr(), getNextSendNum(), addressData,
(byte) 1);
response = commandStationDriveAckResponse.getContent();
}
catch (ProtocolException ex) {
LOGGER.warn("Create CommandStationDriveAck response failed.", ex);
}
return response;
}
protected byte[] processCsAccessoryRequest(BidibCommand bidibMessage) {
LOGGER.info("Process the CsAccessory request: {}", bidibMessage);
byte[] response = null;
try {
CommandStationAccessoryMessage commandStationAccessoryMessage =
(CommandStationAccessoryMessage) bidibMessage;
org.bidib.jbidibc.core.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;
}
protected byte[] processCsRcPlusRequest(BidibCommand 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;
}
protected byte[] processNodeTabGetAllRequest(BidibCommand bidibMessage) {
// reset the local addr
localAddrIndex = 0;
byte tabCount = (byte) subNodes.size();
LOGGER.info("Return number of nodeTabs in current node: {}", tabCount);
byte[] response = null;
try {
NodeTabCountResponse nodeTabCountResponse =
new NodeTabCountResponse(bidibMessage.getAddr(), getNextSendNum(), tabCount);
response = nodeTabCountResponse.getContent();
}
catch (ProtocolException ex) {
LOGGER.warn("Create nodeTabCount response failed.", ex);
}
return response;
}
protected byte[] processNodeTabGetNextRequest(BidibCommand bidibMessage) {
// 02.01.2014 14:50:11.961: send NodeTabGetAllMessage[num=4,type=11,data=[]] : FE 03 00 04 0B 93 FE
// 02.01.2014 14:50:11.974: receive NodeTabCountResponse[[0],num=1,type=136,data=[2]] : 04 00 01 88 02
// 02.01.2014 14:50:11.977: send NodeTabGetNextMessage[num=5,type=12,data=[]] : FE 03 00 05 0C D4 FE
// 02.01.2014 14:50:11.990: receive NodeTabResponse[[0],num=2,type=137,data=[1, 0, 210, 0, 13, 104, 0, 0, 54]] :
// 0C 00 02 89 01 00 D2 00 0D 68 00 00 36
// 02.01.2014 14:50:11.994: send SysMagicMessage[num=6,type=1,data=[]] : FE 03 00 06 01 7C FE
// 02.01.2014 14:50:12.006: receive SysMagicResponse[[0],num=0,type=129,data=[254, 175]] : 05 00 00 81 FE AF
// 02.01.2014 14:50:12.008: send NodeTabGetNextMessage[num=7,type=12,data=[]] : FE 03 00 07 0C 45 FE
// 02.01.2014 14:50:12.022: receive NodeTabResponse[[0],num=1,type=137,data=[1, 1, 5, 0, 13, 107, 0, 105, 234]]
// : 0C 00 01 89 01 01 05 00 0D 6B 00 69 EA
// 02.01.2014 14:50:12.031: send SysMagicMessage[num=0,type=1,data=[]] : FE 04 01 00 00 01 CE FE
// 02.01.2014 14:50:12.038: receive SysMagicResponse[[1],num=0,type=129,data=[254, 175]] : 06 01 00 00 81 FE AF
byte[] response = null;
byte nodeTabVersion = ByteUtils.getLowByte(SimulatorRegistry.getInstance().getNextNodeTabVersion());
byte localAddr = localAddrIndex;
LOGGER.info("get the simulator with local address: {}", localAddr);
String[] nodeAddresses = subNodes.keySet().toArray(new String[0]);
byte addr = ByteUtils.getLowByte(Integer.parseInt(nodeAddresses[localAddr], 16));
SimulatorNode simulator = subNodes.get(nodeAddresses[localAddr]);
long uniqueId = simulator.getUniqueId();
LOGGER.info("localAddr: {}, nodeAddr: {}, uniqueId: {}", localAddr, addr, uniqueId);
try {
NodeTabResponse nodeTabResponse =
new NodeTabResponse(bidibMessage.getAddr(), getNextSendNum(), nodeTabVersion, addr, uniqueId);
response = nodeTabResponse.getContent();
LOGGER.info("Prepared nodeTab response: {}", ByteUtils.bytesToHex(response));
}
catch (ProtocolException ex) {
LOGGER.warn("Create nodeTab response failed.", ex);
}
localAddrIndex++;
return response;
}
protected void processResetRequest(BidibCommand 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]));
}
@EventSubscriber(eventClass = NodeLostEvent.class)
public void nodeLostEvent(NodeLostEvent nodeLostEvent) {
byte[] nodeAddr = nodeLostEvent.getNodeAddr();
// check if the node is a subnode of this node
if (!NodeUtils.isSubNode(nodeAddress, nodeAddr)) {
return;
}
final byte nodeLocalAddress = nodeAddr[nodeAddr.length - 1];
long uniqueId = nodeLostEvent.getUniqueId();
LOGGER
.info("The node lost event was requested, nodeLocalAddress: {}, uniqueId: {}", nodeLocalAddress, uniqueId);
// publish event
byte[] response = null;
byte nodeTabVersion = ByteUtils.getLowByte(SimulatorRegistry.getInstance().getNextNodeTabVersion());
try {
byte addr = nodeLocalAddress;
NodeLostResponse nodeLostResponse =
new NodeLostResponse(nodeAddress, getNextSendNum(), nodeTabVersion, addr, uniqueId);
response = nodeLostResponse.getContent();
LOGGER.info("Prepared nodeLost response: {}", ByteUtils.bytesToHex(response));
}
catch (ProtocolException ex) {
LOGGER.warn("Create nodeLost response failed.", ex);
}
LOGGER.info("Publish the current response: {}", response);
publishResponse(response);
}
@EventSubscriber(eventClass = NodeAvailableEvent.class)
public void nodeAvailableEvent(NodeAvailableEvent nodeAvailableEvent) {
byte[] nodeAddr = nodeAvailableEvent.getNodeAddr();
// check if the node is a subnode of this node
if (!NodeUtils.isSubNode(nodeAddress, nodeAddr)) {
return;
}
final byte nodeLocalAddress = nodeAddr[nodeAddr.length - 1];
long uniqueId = nodeAvailableEvent.getUniqueId();
LOGGER.info("The node available event was requested, nodeLocalAddress: {}, uniqueId: {}", nodeLocalAddress,
uniqueId);
// publish event
byte[] response = null;
byte nodeTabVersion = ByteUtils.getLowByte(SimulatorRegistry.getInstance().getNextNodeTabVersion());
try {
byte addr = nodeLocalAddress;
NodeNewResponse nodeNewResponse =
new NodeNewResponse(nodeAddress, getNextSendNum(), nodeTabVersion, addr, uniqueId);
response = nodeNewResponse.getContent();
LOGGER.info("Prepared nodeNew response: {}", ByteUtils.bytesToHex(response));
}
catch (ProtocolException ex) {
LOGGER.warn("Create nodeNew response failed.", ex);
}
LOGGER.info("Publish the current response: {}", response);
publishResponse(response);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy