All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bidib.wizard.simulation.OneControlSimulator Maven / Gradle / Ivy

There is a newer version: 2.0.0-M1
Show newest version
package org.bidib.wizard.simulation;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.collections4.MapUtils;
import org.bidib.jbidibc.core.AddressData;
import org.bidib.jbidibc.core.BidibLibrary;
import org.bidib.jbidibc.core.BidibPort;
import org.bidib.jbidibc.core.Feature;
import org.bidib.jbidibc.core.LcConfigX;
import org.bidib.jbidibc.core.enumeration.InputPortEnum;
import org.bidib.jbidibc.core.enumeration.LcOutputType;
import org.bidib.jbidibc.core.exception.ProtocolException;
import org.bidib.jbidibc.core.message.BidibCommand;
import org.bidib.jbidibc.core.message.FeedbackAddressResponse;
import org.bidib.jbidibc.core.message.FeedbackConfidenceResponse;
import org.bidib.jbidibc.core.message.FeedbackGetRangeMessage;
import org.bidib.jbidibc.core.message.FeedbackMultipleResponse;
import org.bidib.jbidibc.core.message.LcConfigXGetMessage;
import org.bidib.jbidibc.core.message.LcConfigXResponse;
import org.bidib.jbidibc.core.message.LcConfigXSetMessage;
import org.bidib.jbidibc.core.message.LcKeyMessage;
import org.bidib.jbidibc.core.message.LcKeyResponse;
import org.bidib.jbidibc.core.message.LcNotAvailableResponse;
import org.bidib.jbidibc.core.message.LcOutputQueryMessage;
import org.bidib.jbidibc.core.message.LcStatResponse;
import org.bidib.jbidibc.core.port.BytePortConfigValue;
import org.bidib.jbidibc.core.port.PortConfigValue;
import org.bidib.jbidibc.core.port.ReconfigPortConfigValue;
import org.bidib.jbidibc.core.utils.ByteUtils;
import org.bidib.jbidibc.core.utils.MessageUtils;
import org.bidib.jbidibc.simulation.SwitchingFunctionsNode;
import org.bidib.jbidibc.simulation.net.SimulationBidibMessageProcessor;
import org.bidib.wizard.comm.FeedbackPortStatus;
import org.bidib.wizard.comm.InputPortStatus;
import org.bidib.wizard.mvc.main.model.FeedbackAddressData;
import org.bidib.wizard.mvc.main.model.FeedbackPort;
import org.bidib.wizard.mvc.main.model.GenericPort;
import org.bidib.wizard.simulation.events.InputPortStatusEvent;
import org.bidib.wizard.simulation.ports.GenericSimulationPort;
import org.bushe.swing.event.EventBus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OneControlSimulator extends LightControlSimulator implements SwitchingFunctionsNode {
    private static final Logger LOGGER = LoggerFactory.getLogger(OneControlSimulator.class);

    private static final String SIMULATION_PANEL_CLASS = "org.bidib.wizard.mvc.simulation.view.panel.LightControlPanel";

    private final Map genericPorts = new HashMap();

    private final Map feedbackPorts = new HashMap();

    private final AtomicBoolean statusFreeze = new AtomicBoolean();

    private final AtomicBoolean statusValid = new AtomicBoolean();

    private final AtomicBoolean statusSignal = new AtomicBoolean();

    public OneControlSimulator(byte[] nodeAddress, long uniqueId, boolean autoAddFeature,
        SimulationBidibMessageProcessor messageReceiver) {
        super(nodeAddress, uniqueId, autoAddFeature, messageReceiver);
    }

    private void setupFeedbackPorts() {
        for (int id = 0; id < 16; id++) {
            FeedbackPort port = new FeedbackPort();

            port.setId(id);
            port.setStatus(id % 3 == 0 ? FeedbackPortStatus.FREE : FeedbackPortStatus.OCCUPIED);
            feedbackPorts.put(id, port);
        }
    }

    @Override
    protected void prepareFeatures() {
        LOGGER.info("Prepare the features.");
        super.prepareFeatures();

        Feature feature = getFeature(BidibLibrary.FEATURE_CTRL_PORT_FLAT_MODEL);
        if (feature != null) {
            int numPorts = feature.getValue();

            LOGGER.info("Create generic ports, numPorts: {}", numPorts);

            for (int portNumber = 0; portNumber < numPorts; portNumber++) {
                GenericSimulationPort port = new GenericSimulationPort(portNumber);

                genericPorts.put(portNumber, port);
            }
        }
    }

    @Override
    public boolean isPortFlatModelAvailable() {
        Feature feature = getFeature(BidibLibrary.FEATURE_CTRL_PORT_FLAT_MODEL);
        if (feature != null && feature.getValue() > 0) {
            return true;
        }
        return false;
    }

    @Override
    public LcOutputType getPortType(BidibPort bidibPort) {
        int portNumber = bidibPort.getPortNumber(getPortModel());
        LOGGER.info("getPortType for portNumber: {}", portNumber);
        LcOutputType outputType = null;
        GenericPort genericPort = genericPorts.get(portNumber);
        if (genericPort != null) {

            outputType = genericPort.getCurrentPortType();
        }

        return outputType;
    }

    @Override
    public void start() {
        LOGGER.info("Start the simulator for address: {}", getAddress());

        // prepare the feedback ports
        setupFeedbackPorts();

        super.start();

        if (!MapUtils.isEmpty(genericPorts)) {
            int index = 0;

            for (int portNum = 0; portNum < servoPortCount; portNum++) {
                GenericSimulationPort genericPort = genericPorts.get(portNum + index);
                genericPort.setCurrentPortType(LcOutputType.SERVOPORT, 0x0004);
            }
            index += servoPortCount;

            for (int portNum = 0; portNum < switchPortCount; portNum++) {
                GenericSimulationPort genericPort = genericPorts.get(portNum + index);
                genericPort.setCurrentPortType(LcOutputType.SWITCHPORT, 0x0001);
            }
            // index += switchPortCount;

            // TODO this is a hack for the OneControl
            index = inputPortOffset;
            LOGGER.info("Set the port type for input ports, index: {}", index);
            for (int portNum = 0; portNum < inputPortCount; portNum++) {
                GenericSimulationPort genericPort = genericPorts.get(portNum + index);
                genericPort.setCurrentPortType(LcOutputType.INPUTPORT, 0x8001);
            }
        }
    }

    @Override
    public String getSimulationPanelClass() {
        return SIMULATION_PANEL_CLASS;
    }

    @Override
    protected byte[] prepareResponse(BidibCommand bidibMessage) {

        byte[] response = null;
        switch (ByteUtils.getInt(bidibMessage.getType())) {
            case BidibLibrary.MSG_BM_GET_RANGE:
                response = processBmGetRangeRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_BM_MIRROR_MULTIPLE:
                processBmMirrorMultipleRequest(bidibMessage);
                break;

            case BidibLibrary.MSG_BM_ADDR_GET_RANGE:
                processBmAddrGetRangeRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_BM_GET_CONFIDENCE:
                response = processBmGetConfidenceRequest(bidibMessage);
                break;
            default:
                response = super.prepareResponse(bidibMessage);
                break;
        }
        return response;
    }

    protected byte[] processBmGetRangeRequest(BidibCommand bidibMessage) {
        LOGGER.info("Process the FeedbackGetRangeMessage: {}", bidibMessage);

        byte[] response = null;
        try {
            FeedbackGetRangeMessage feedbackGetRangeMessage = (FeedbackGetRangeMessage) bidibMessage;
            byte baseAddress = feedbackGetRangeMessage.getBegin();
            int end = feedbackGetRangeMessage.getEnd();
            byte feedbackSize =
                ByteUtils.getLowByte(feedbackGetRangeMessage.getEnd() - feedbackGetRangeMessage.getBegin());

            byte value = 0x00;
            int index = 0;

            byte[] feedbackMultiple = new byte[feedbackSize / 8];
            int position = feedbackMultiple.length;

            for (int portNum = end; portNum > baseAddress; portNum--) {
                value = (byte) ((value & 0xFF) << 1);
                FeedbackPort fbp = feedbackPorts.get(portNum - 1);
                byte status = (byte) (fbp.getStatus().getType().getType() & 0x01);
                value |= status;
                index++;
                if (index > 7) {
                    feedbackMultiple[position - 1] = value;
                    value = 0;
                    index = 0;
                    position--;
                }
            }

            LOGGER.info("Prepared feedback multiple: {}", ByteUtils.bytesToHex(feedbackMultiple));

            FeedbackMultipleResponse feedbackMultipleResponse =
                new FeedbackMultipleResponse(bidibMessage.getAddr(), getNextSendNum(), baseAddress, feedbackSize,
                    feedbackMultiple);
            response = feedbackMultipleResponse.getContent();
        }
        catch (ProtocolException ex) {
            LOGGER.warn("Create feedbackMultiple response failed.", ex);
        }
        return response;
    }

    protected void processBmMirrorMultipleRequest(BidibCommand bidibMessage) {
        LOGGER.info("Process the FeedbackMirrorMultipleMessage: {}, do nothing ...", bidibMessage);
    }

    protected void processBmAddrGetRangeRequest(BidibCommand bidibMessage) {

        try {
            for (FeedbackPort port : feedbackPorts.values()) {

                int detectorNumber = port.getId();
                Collection bidibAddresses = new ArrayList<>();
                Collection addresses = port.getAddresses();
                for (FeedbackAddressData addressData : addresses) {
                    AddressData bidibAddress = new AddressData(addressData.getAddress(), addressData.getType());
                    bidibAddresses.add(bidibAddress);
                }
                FeedbackAddressResponse feedbackAddressResponse =
                    new FeedbackAddressResponse(bidibMessage.getAddr(), getNextSendNum(), detectorNumber,
                        bidibAddresses);
                byte[] response = feedbackAddressResponse.getContent();
                LOGGER.info("Prepare feedbackAddressResponse: {}", ByteUtils.bytesToHex(response));
                sendSpontanousResponse(response);
            }
        }
        catch (ProtocolException ex) {
            LOGGER.warn("Create feedbackAddress response failed.", ex);
        }
    }

    protected byte[] processBmGetConfidenceRequest(BidibCommand bidibMessage) {
        byte[] response = null;
        try {

            byte valid = (byte) (statusValid.get() ? 1 : 0);
            byte freeze = (byte) (statusFreeze.get() ? 1 : 0);
            byte signal = (byte) (statusSignal.get() ? 1 : 0);

            // TODO if more than a single GBM16T is attached we must set more bits? See 4.7.4. Uplink: Nachrichten für
            // Belegtmelder --> MSG_BM_CONFIDENCE
            // Test with real system: See MainMessageListener.confidence()

            FeedbackConfidenceResponse feedbackConfidenceResponse =
                new FeedbackConfidenceResponse(bidibMessage.getAddr(), getNextSendNum(), valid, freeze, signal);
            response = feedbackConfidenceResponse.getContent();
        }
        catch (ProtocolException ex) {
            LOGGER.warn("Create feedbackConfidence response failed.", ex);
        }
        return response;
    }

    protected byte[] processLcConfigXSetRequest(BidibCommand bidibMessage) {

        LOGGER.info("Process the LcConfigXSet request: {}", bidibMessage);
        byte[] response = null;

        if (getFlatPortModelPortCount() > 0) {
            try {
                LcConfigXSetMessage lcConfigXSetMessage = (LcConfigXSetMessage) bidibMessage;
                int outputNumber = lcConfigXSetMessage.getPortNumber(getPortModel());
                LcOutputType outputType = lcConfigXSetMessage.getPortType(getPortModel());

                GenericPort port = null;
                port = genericPorts.get(Integer.valueOf(outputNumber));
                LOGGER.info("Set LcConfig for output number: {}, port: {}", outputNumber, port);

                BidibPort bidibPort = prepareBidibPort(getPortModel(), outputType, outputNumber);

                if (port != null) {

                    // the problem here is that the BIDIB_PCFG_RECONFIG overwrites the supported port types
                    LcConfigX lcConfigX = lcConfigXSetMessage.getLcConfigX();
                    ReconfigPortConfigValue reconfig =
                        (ReconfigPortConfigValue) lcConfigX.getPortConfig().get(BidibLibrary.BIDIB_PCFG_RECONFIG);
                    if (reconfig != null) {
                        // we must keep the supported port types
                        Integer supportedPortTypes = port.getSupportedPortTypes();
                        if (supportedPortTypes != null) {
                            ReconfigPortConfigValue newReconfig =
                                new ReconfigPortConfigValue(reconfig.getCurrentOutputType().getType(),
                                    supportedPortTypes);
                            LOGGER.info("Prepared BIDIB_PCFG_RECONFIG to replace: {}", newReconfig);
                            lcConfigX.getPortConfig().put(BidibLibrary.BIDIB_PCFG_RECONFIG, newReconfig);
                        }
                    }
                    port.setPortConfig(lcConfigX.getPortConfig());

                    byte[] content = MessageUtils.getCodedPortConfig(lcConfigX, getPortModel());

                    // TODO remove this test
                    if (outputNumber == 5) {
                        content = new byte[] { 0x00, 0x05, 0x00, 0x0C };
                    }

                    LcConfigXResponse lcConfigXResponse =
                        new LcConfigXResponse(bidibMessage.getAddr(), getNextSendNum(), content);
                    response = lcConfigXResponse.getContent();
                }
                else {
                    LOGGER.warn("No port assigned!");
                    LcNotAvailableResponse magicResponse =
                        new LcNotAvailableResponse(bidibMessage.getAddr(), getNextSendNum(), bidibPort);
                    response = magicResponse.getContent();
                }
            }
            catch (ProtocolException ex) {
                LOGGER.warn("Create LcConfigX response failed.", ex);
            }
        }
        else {
            response = super.processLcConfigXSetRequest(bidibMessage);
        }
        return response;
    }

    protected byte[] processLcConfigXGetRequest(BidibCommand bidibMessage) {
        LOGGER.info("Process the LcConfigXGet request: {}", bidibMessage);
        byte[] response = null;

        if (getFlatPortModelPortCount() > 0) {

            try {
                LcConfigXGetMessage lcConfigXGetMessage = (LcConfigXGetMessage) bidibMessage;
                int outputNumber = lcConfigXGetMessage.getPortNumber(getPortModel());
                LcOutputType outputType = lcConfigXGetMessage.getPortType(getPortModel());

                GenericPort port = null;
                Map> values = new LinkedHashMap<>();

                port = genericPorts.get(Integer.valueOf(outputNumber));

                BidibPort bidibPort = prepareBidibPort(getPortModel(), outputType, outputNumber);

                if (port != null) {

                    if (outputNumber >= 0 && outputNumber < 4) { // 4 servo ports
                        values.put(BidibLibrary.BIDIB_PCFG_RECONFIG,
                            new ReconfigPortConfigValue(Integer.valueOf(0x000402)));
                    }
                    else if (outputNumber >= 4 && outputNumber < (4 + 16)) { // 16 power ports
                        values.put(BidibLibrary.BIDIB_PCFG_RECONFIG,
                            new ReconfigPortConfigValue(Integer.valueOf(0x000100)));

                        values.put(BidibLibrary.BIDIB_PCFG_IO_CTRL, new BytePortConfigValue(Byte.valueOf((byte) 0x00)));
                        values.put(BidibLibrary.BIDIB_PCFG_TICKS, new BytePortConfigValue(Byte.valueOf((byte) 0x0F)));
                    }
                    else { // GPIO are all input ports
                        values.put(BidibLibrary.BIDIB_PCFG_RECONFIG,
                            new ReconfigPortConfigValue(Integer.valueOf(0x80010F)));

                        values.put(BidibLibrary.BIDIB_PCFG_IO_CTRL, new BytePortConfigValue(Byte.valueOf((byte) 0x00)));
                        values.put(BidibLibrary.BIDIB_PCFG_TICKS, new BytePortConfigValue(Byte.valueOf((byte) 0x00)));
                    }

                    // TODO remove this test
                    if (outputNumber == 2) {
                        values.put(BidibLibrary.BIDIB_PCFG_NONE, new BytePortConfigValue((byte) 12));
                    }

                    LOGGER.info("Return config of port: {}", port);
                    LcConfigX lcConfigX = new LcConfigX(bidibPort, values);

                    LcConfigXResponse lcConfigXResponse =
                        new LcConfigXResponse(bidibMessage.getAddr(), getNextSendNum(),
                            MessageUtils.getCodedPortConfig(lcConfigX, getPortModel()));
                    response = lcConfigXResponse.getContent();
                }
                else {
                    LOGGER.warn("No port available with port number: {}", outputNumber);
                    LcNotAvailableResponse notAvailableResponse =
                        new LcNotAvailableResponse(bidibMessage.getAddr(), getNextSendNum(), bidibPort);
                    response = notAvailableResponse.getContent();
                }
            }
            catch (ProtocolException ex) {
                LOGGER.warn("Create LcConfigX response failed.", ex);
            }
        }
        else {
            response = super.processLcConfigXGetRequest(bidibMessage);
        }
        return response;
    }

    protected void processLcConfigXGetAllRequest(BidibCommand bidibMessage) {
        LOGGER.info("Process the LcConfigXGetAll request: {}", bidibMessage);

        if (getFlatPortModelPortCount() > 0) {
            LcOutputType outputType = LcOutputType.SWITCHPORT;

            Map> values = new LinkedHashMap<>();

            try {
                for (GenericPort port : genericPorts.values()) {
                    int portNumber = port.getPortNumber();
                    values.clear();

                    if (portNumber >= 0 && portNumber < 4) { // 4 servo ports
                        values.put(BidibLibrary.BIDIB_PCFG_RECONFIG,
                            new ReconfigPortConfigValue(Integer.valueOf(0x000402)));
                    }
                    else if (portNumber >= 4 && portNumber < (4 + 16)) { // 16 power ports
                        values.put(BidibLibrary.BIDIB_PCFG_RECONFIG,
                            new ReconfigPortConfigValue(Integer.valueOf(0x000100)));

                        values.put(BidibLibrary.BIDIB_PCFG_IO_CTRL, new BytePortConfigValue(Byte.valueOf((byte) 0x00)));
                        values.put(BidibLibrary.BIDIB_PCFG_TICKS, new BytePortConfigValue(Byte.valueOf((byte) 0x0F)));
                    }
                    else { // GPIO are all input ports
                        values.put(BidibLibrary.BIDIB_PCFG_RECONFIG,
                            new ReconfigPortConfigValue(Integer.valueOf(0x80010F)));

                        values.put(BidibLibrary.BIDIB_PCFG_IO_CTRL, new BytePortConfigValue(Byte.valueOf((byte) 0x00)));
                        values.put(BidibLibrary.BIDIB_PCFG_TICKS, new BytePortConfigValue(Byte.valueOf((byte) 0x00)));
                    }

                    // TODO remove this test
                    if (portNumber == 6) {
                        values.put(BidibLibrary.BIDIB_PCFG_NONE, new BytePortConfigValue((byte) 12));
                    }

                    LOGGER.info("Return config of port: {}", port);
                    BidibPort bidibPort = prepareBidibPort(getPortModel(), outputType, portNumber);
                    LcConfigX lcConfigX = new LcConfigX(bidibPort, values);

                    LcConfigXResponse lcConfigXResponse =
                        new LcConfigXResponse(bidibMessage.getAddr(), getNextSendNum(),
                            MessageUtils.getCodedPortConfig(lcConfigX, getPortModel()));
                    byte[] response = lcConfigXResponse.getContent();

                    LOGGER.info("Prepared lcConfigXResponse: {}", ByteUtils.bytesToHex(response));
                    sendSpontanousResponse(response);
                }
            }
            catch (ProtocolException ex) {
                LOGGER.warn("Create LcConfigXResponse response failed.", ex);
            }
        }
        else {
            super.processLcConfigXGetAllRequest(bidibMessage);
        }
    }

    protected byte[] processLcOutputQueryRequest(BidibCommand bidibMessage) {

        LOGGER.info("Process the LcOutputQuery request: {}", bidibMessage);
        byte[] response = null;

        if (getFlatPortModelPortCount() > 0) {
            byte portState = 0;

            try {
                LcOutputQueryMessage lcOutputQueryMessage = (LcOutputQueryMessage) bidibMessage;
                LcOutputType outputType = lcOutputQueryMessage.getPortType(getPortModel());
                int outputNumber = lcOutputQueryMessage.getPortNumber(getPortModel());

                GenericPort port = genericPorts.get(Integer.valueOf(outputNumber));

                BidibPort bidibPort = prepareBidibPort(getPortModel(), outputType, outputNumber);

                if (port != null) {
                    portState = ByteUtils.getLowByte(0xFF);
                }
                else {
                    LOGGER.warn("No port available with portNumber: {}", outputNumber);
                }
                LcStatResponse lcStatResponse =
                    new LcStatResponse(bidibMessage.getAddr(), getNextSendNum(), bidibPort, portState);
                response = lcStatResponse.getContent();
            }
            catch (ProtocolException ex) {
                LOGGER.warn("Create LcStat response failed.", ex);
            }
        }
        else {
            response = super.processLcOutputQueryRequest(bidibMessage);
        }
        return response;
    }

    protected byte[] processLcKeyQueryRequest(BidibCommand bidibMessage) {
        LOGGER.info("Process the LcKeyQuery request: {}", bidibMessage);
        byte[] response = null;

        if (getFlatPortModelPortCount() > 0) {
            byte keyState = 0;
            GenericSimulationPort port = null;
            try {
                LcKeyMessage lcKeyMessage = (LcKeyMessage) bidibMessage;
                int portNumber = lcKeyMessage.getKeyNumber();

                port = genericPorts.get(Integer.valueOf(portNumber));

                if (port != null) {
                    keyState = port.getPortStatus();
                }
                else {
                    LOGGER.warn("No port available with portNumber: {}", portNumber);
                }

                LcKeyResponse lcKeyResponse =
                    new LcKeyResponse(bidibMessage.getAddr(), getNextSendNum(), ByteUtils.getLowByte(portNumber),
                        keyState);
                response = lcKeyResponse.getContent();
            }
            catch (ProtocolException ex) {
                LOGGER.warn("Create LcKey response failed.", ex);
            }

            if (port != null) {
                publishInputPortChange(port);
            }
        }
        else {
            response = super.processLcKeyQueryRequest(bidibMessage);
        }
        return response;
    }

    private void publishInputPortChange(GenericSimulationPort port) {

        InputPortStatus status = InputPortStatus.valueOf(InputPortEnum.valueOf(port.getPortStatus()));

        LOGGER.info("The inputport status has changed, notify the listeners, nodeAddress: {}", nodeAddress);
        EventBus.publish(new InputPortStatusEvent(ByteUtils.bytesToHex(nodeAddress), port.getPortNumber(), status));
    }

    protected void changeInputPortStatus(int portNum) {

        GenericSimulationPort port = genericPorts.get(portNum);
        if (port != null) {

            InputPortStatus portStatus = InputPortStatus.valueOf(InputPortEnum.valueOf(port.getPortStatus()));

            switch (portStatus) {
                case OFF:
                    port.setPortStatus(InputPortStatus.ON.getType().getType());
                    break;
                default:
                    port.setPortStatus(InputPortStatus.OFF.getType().getType());
                    break;
            }

            // prepare the request
            final LcKeyMessage lcKeyMessage = new LcKeyMessage(
                portNum) {
                @Override
                public byte[] getAddr() {
                    return getNodeAddress();
                }
            };
            processRequest(lcKeyMessage);
        }
        else {
            LOGGER.warn("The requested input port is not available: {}", portNum);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy