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

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

The newest version!
package org.bidib.wizard.simulation;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.swing.Timer;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.bidib.jbidibc.messages.AddressData;
import org.bidib.jbidibc.messages.BidibLibrary;
import org.bidib.jbidibc.messages.BidibPort;
import org.bidib.jbidibc.messages.Feature;
import org.bidib.jbidibc.messages.FeedbackAddressData;
import org.bidib.jbidibc.messages.LcConfigX;
import org.bidib.jbidibc.messages.enums.AddressTypeEnum;
import org.bidib.jbidibc.messages.enums.EnrailmentDirectionEnum;
import org.bidib.jbidibc.messages.enums.InputPortEnum;
import org.bidib.jbidibc.messages.enums.LcOutputType;
import org.bidib.jbidibc.messages.enums.LightPortEnum;
import org.bidib.jbidibc.messages.enums.PortConfigStatus;
import org.bidib.jbidibc.messages.enums.PortModelEnum;
import org.bidib.jbidibc.messages.enums.SwitchPortEnum;
import org.bidib.jbidibc.messages.exception.ProtocolException;
import org.bidib.jbidibc.messages.message.AccessorySetMessage;
import org.bidib.jbidibc.messages.message.AccessoryStateResponse;
import org.bidib.jbidibc.messages.message.BidibMessage;
import org.bidib.jbidibc.messages.message.BidibMessageInterface;
import org.bidib.jbidibc.messages.message.BidibRequestFactory;
import org.bidib.jbidibc.messages.message.FeedbackAddressResponse;
import org.bidib.jbidibc.messages.message.FeedbackConfidenceResponse;
import org.bidib.jbidibc.messages.message.FeedbackFreeResponse;
import org.bidib.jbidibc.messages.message.FeedbackGetRangeMessage;
import org.bidib.jbidibc.messages.message.FeedbackMultipleResponse;
import org.bidib.jbidibc.messages.message.FeedbackOccupiedResponse;
import org.bidib.jbidibc.messages.message.LcConfigXGetMessage;
import org.bidib.jbidibc.messages.message.LcConfigXResponse;
import org.bidib.jbidibc.messages.message.LcConfigXSetMessage;
import org.bidib.jbidibc.messages.message.LcKeyMessage;
import org.bidib.jbidibc.messages.message.LcKeyResponse;
import org.bidib.jbidibc.messages.message.LcNotAvailableResponse;
import org.bidib.jbidibc.messages.message.LcOutputMessage;
import org.bidib.jbidibc.messages.message.LcPortQueryAllMessage;
import org.bidib.jbidibc.messages.message.LcPortQueryMessage;
import org.bidib.jbidibc.messages.message.LcStatResponse;
import org.bidib.jbidibc.messages.port.BytePortConfigValue;
import org.bidib.jbidibc.messages.port.PortConfigUtils;
import org.bidib.jbidibc.messages.port.PortConfigValue;
import org.bidib.jbidibc.messages.port.ReconfigPortConfigValue;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.bidib.jbidibc.messages.utils.NodeUtils;
import org.bidib.jbidibc.simulation.SimulationBidibMessageProcessor;
import org.bidib.jbidibc.simulation.SwitchingFunctionsNode;
import org.bidib.jbidibc.simulation.annotation.BidibNodeSimulator;
import org.bidib.jbidibc.simulation.annotation.BidibNodeSimulators;
import org.bidib.jbidibc.simulation.nodes.FlatInputPortType;
import org.bidib.jbidibc.simulation.nodes.FlatPortType;
import org.bidib.jbidibc.simulation.nodes.FlatServoPortType;
import org.bidib.jbidibc.simulation.nodes.FlatSwitchPortType;
import org.bidib.jbidibc.simulation.nodes.PortParamsType;
import org.bidib.wizard.model.ports.FeedbackPort;
import org.bidib.wizard.model.ports.GenericPort;
import org.bidib.wizard.model.ports.InputPort;
import org.bidib.wizard.model.ports.LightPort;
import org.bidib.wizard.model.ports.Port;
import org.bidib.wizard.model.ports.ServoPort;
import org.bidib.wizard.model.ports.SwitchPort;
import org.bidib.wizard.model.status.FeedbackPortStatus;
import org.bidib.wizard.model.status.InputPortStatus;
import org.bidib.wizard.model.status.LightPortStatus;
import org.bidib.wizard.model.status.SwitchPortStatus;
import org.bidib.wizard.simulation.events.FeedbackConfidenceSetEvent;
import org.bidib.wizard.simulation.events.FeedbackConfidenceStatusEvent;
import org.bidib.wizard.simulation.events.FeedbackPortSetStatusEvent;
import org.bidib.wizard.simulation.events.FeedbackPortStatusEvent;
import org.bidib.wizard.simulation.events.InputPortStatusEvent;
import org.bidib.wizard.simulation.events.LightPortStatusEvent;
import org.bidib.wizard.simulation.events.ServoPortStatusEvent;
import org.bidib.wizard.simulation.events.SwitchPortStatusEvent;
import org.bidib.wizard.simulation.ports.GenericSimulationPort;
import org.bushe.swing.event.EventBus;
import org.bushe.swing.event.annotation.EventSubscriber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@BidibNodeSimulators({ @BidibNodeSimulator(vid = "13", pid = "117"), @BidibNodeSimulator(vid = "13", pid = "140"),
    @BidibNodeSimulator(vid = "13", pid = "141"), @BidibNodeSimulator(vid = "13", pid = "142"),
    @BidibNodeSimulator(vid = "13", pid = "122"), @BidibNodeSimulator(vid = "13", pid = "143"),
    @BidibNodeSimulator(vid = "13", pid = "144"), @BidibNodeSimulator(vid = "13", pid = "145") })
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.simulation.client.view.panel.OneControlPanel";

    protected static final int NUM_OF_FEEDBACK_PORTS = 20;

    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, final BidibRequestFactory bidibRequestFactory) {
        super(nodeAddress, uniqueId, autoAddFeature, messageReceiver, bidibRequestFactory);
    }

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

        features.remove(new Feature(BidibLibrary.FEATURE_ACCESSORY_MACROMAPPED, 2));
        features.add(new Feature(BidibLibrary.FEATURE_ACCESSORY_MACROMAPPED, 8));

        if (MapUtils.isNotEmpty(feedbackPorts)) {
            features.add(new Feature(BidibLibrary.FEATURE_BM_SECACK_AVAILABLE, 1));
            features.add(new Feature(BidibLibrary.FEATURE_BM_SECACK_ON, 0));

            features.add(new Feature(BidibLibrary.FEATURE_BM_ON, 1));
        }
    }

    @Override
    public void postConstruct() {
        super.postConstruct();

        features.add(new Feature(BidibLibrary.FEATURE_BM_SIZE, feedbackPorts.size()));

        Feature feature = getFeature(BidibLibrary.FEATURE_CTRL_PORT_FLAT_MODEL);
        if (feature != null && MapUtils.isEmpty(genericPorts)) {
            LOGGER.info("The current simulator has the flat model configured. Prepare the generic ports.");
            int numPorts = feature.getValue();

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

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

                port
                    .setPortStatus(portNumber % 2 == 0 ? InputPortStatus.ON.getType().getType()
                        : InputPortStatus.OFF.getType().getType());

                genericPorts.put(portNumber, port);
            }
        }
        else {
            LOGGER.info("Skip init the ports because the ports are available already.");

            if (MapUtils.isNotEmpty(genericPorts)) {
                LOGGER.info("Set the feature FEATURE_CTRL_PORT_FLAT_MODEL to value: {}", genericPorts.size());
                features.add(new Feature(BidibLibrary.FEATURE_CTRL_PORT_FLAT_MODEL, genericPorts.size()));
            }
        }
    }

    @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());

        // 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);

                Map> portConfig = new LinkedHashMap<>();
                portConfig.put(BidibLibrary.BIDIB_PCFG_SERVO_ADJ_L, new BytePortConfigValue(ByteUtils.getLowByte(20)));
                portConfig.put(BidibLibrary.BIDIB_PCFG_SERVO_ADJ_H, new BytePortConfigValue(ByteUtils.getLowByte(150)));
                portConfig.put(BidibLibrary.BIDIB_PCFG_SERVO_SPEED, new BytePortConfigValue(ByteUtils.getLowByte(4)));
                genericPort.setPortConfigX(portConfig);

                genericPort.setPortValue(ServoPort.getAbsoluteValue((portNum % 4) * 25));
            }
            index += servoPortCount;

            for (int portNum = 0; portNum < switchPortCount; portNum++) {
                GenericSimulationPort genericPort = genericPorts.get(portNum + index);

                // only even port can be a switchpair port
                int mask = (1 << BidibLibrary.BIDIB_PORTTYPE_SWITCH | 1 << BidibLibrary.BIDIB_PORTTYPE_SWITCHPAIR);
                if ((portNum & 0x01) == 0x01) {
                    mask = (1 << BidibLibrary.BIDIB_PORTTYPE_SWITCH);
                    genericPort.setCurrentPortType(LcOutputType.SWITCHPORT, mask);
                }
                else {
                    // switchPair ports are active by default
                    genericPort.setCurrentPortType(LcOutputType.SWITCHPAIRPORT, mask);
                }

                Map> portConfig = genericPort.getPortConfigX();
                portConfig.put(BidibLibrary.BIDIB_PCFG_LOAD_TYPE, new BytePortConfigValue(Byte.valueOf((byte) 0x00)));
                portConfig.put(BidibLibrary.BIDIB_PCFG_TICKS, new BytePortConfigValue(Byte.valueOf((byte) 0x30)));

                genericPort.setPortConfigX(portConfig);
            }

            // 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);
                int mask =
                    (1 << BidibLibrary.BIDIB_PORTTYPE_SWITCH | 1 << BidibLibrary.BIDIB_PORTTYPE_SWITCHPAIR
                        | 1 << BidibLibrary.BIDIB_PORTTYPE_INPUT);
                genericPort.setCurrentPortType(LcOutputType.INPUTPORT, mask /* 0x8001 */);

                LOGGER.info("The current port is configured as INPUT port: {}", genericPort);

                Map> portConfig = genericPort.getPortConfigX();
                portConfig.remove(BidibLibrary.BIDIB_PCFG_RECONFIG);
                portConfig.put(BidibLibrary.BIDIB_PCFG_LOAD_TYPE, new BytePortConfigValue(Byte.valueOf((byte) 0x00)));
                portConfig.put(BidibLibrary.BIDIB_PCFG_INPUT_CTRL, new BytePortConfigValue(Byte.valueOf((byte) 0x00)));
                genericPort.setPortConfigX(portConfig);
            }

            GenericSimulationPort simPort = null;
            LOGGER.info("Prepare CV for OneControl.");

            // TODO fix the CV for the current OneControl

            for (Entry cv : configurationVariables.entrySet()) {
                switch (cv.getKey()) {
                    case "437":
                        simPort = genericPorts.get(inputPortOffset);
                        break;
                    case "440":
                        simPort = genericPorts.get(inputPortOffset + 1);
                        break;
                    case "443":
                        simPort = genericPorts.get(inputPortOffset + 2);
                        break;
                    case "446":
                        simPort = genericPorts.get(inputPortOffset + 3);
                        break;
                    case "449":
                        simPort = genericPorts.get(inputPortOffset + 4);
                        break;
                    case "452":
                        simPort = genericPorts.get(inputPortOffset + 5);
                        break;
                    case "455":
                        simPort = genericPorts.get(inputPortOffset + 6);
                        break;
                    case "458":
                        simPort = genericPorts.get(inputPortOffset + 7);
                        break;
                    case "461":
                        simPort = genericPorts.get(inputPortOffset + 8);
                        break;
                    case "464":
                        simPort = genericPorts.get(inputPortOffset + 9);
                        break;
                    case "467":
                        simPort = genericPorts.get(inputPortOffset + 10);
                        break;
                    case "470":
                        simPort = genericPorts.get(inputPortOffset + 11);
                        break;
                    case "473":
                        simPort = genericPorts.get(inputPortOffset + 12);
                        break;
                    case "476":
                        simPort = genericPorts.get(inputPortOffset + 13);
                        break;
                    case "479":
                        simPort = genericPorts.get(inputPortOffset + 14);
                        break;
                    case "482":
                        simPort = genericPorts.get(inputPortOffset + 15);
                        break;
                    default:
                        break;
                }

                // if (simPort != null) {
                // int mask =
                // (1 << BidibLibrary.BIDIB_PORTTYPE_SWITCH | 1 << BidibLibrary.BIDIB_PORTTYPE_SWITCHPAIR
                // | 1 << BidibLibrary.BIDIB_PORTTYPE_INPUT);
                // switch (cv.getValue()) {
                // case "0":
                // simPort.setCurrentPortType(LcOutputType.SWITCHPORT, mask);
                // break;
                // default:
                // simPort.setCurrentPortType(LcOutputType.INPUTPORT, mask);
                // break;
                // }
                //
                // LOGGER.info("Prepared port: {}", simPort);
                // }

                simPort = null;
            }

        }
    }

    @Override
    public void stop() {

        super.stop();
    }

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

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

        uniqueId = NodeUtils.setHasFeedbackFunctions(uniqueId);
        LOGGER.info("Set the feeback ports flag in the class. New uniqueId: {}", ByteUtils.formatHexUniqueId(uniqueId));
    }

    @Override
    protected byte[] prepareResponse(BidibMessageInterface 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_MIRROR_OCC:
                processBmMirrorOccupiedRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_BM_MIRROR_FREE:
                processBmMirrorFreeRequest(bidibMessage);
                break;

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

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

        byte[] response = null;
        try {
            FeedbackGetRangeMessage feedbackGetRangeMessage = (FeedbackGetRangeMessage) bidibMessage;
            int baseAddress = feedbackGetRangeMessage.getBeginRange();
            int end = feedbackGetRangeMessage.getEndRange();
            int feedbackSize = feedbackGetRangeMessage.getEndRange() - feedbackGetRangeMessage.getBeginRange();

            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 = 0;
                if (fbp != null) {
                    status = ByteUtils.getLowByte(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(),
                    ByteUtils.getLowByte(baseAddress), ByteUtils.getLowByte(feedbackSize), feedbackMultiple);
            response = feedbackMultipleResponse.getContent();
        }
        catch (ProtocolException ex) {
            LOGGER.warn("Create feedbackMultiple response failed.", ex);
        }
        catch (Exception ex) {
            LOGGER.warn("Create feedbackMultiple response failed.", ex);
        }
        return response;
    }

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

    @Override
    protected void processBmMirrorOccupiedRequest(BidibMessageInterface bidibMessage) {
        LOGGER.info("Process the processBmMirrorOccupiedRequest: {}, do nothing ...", bidibMessage);
    }

    @Override
    protected void processBmMirrorFreeRequest(BidibMessageInterface bidibMessage) {
        LOGGER.info("Process the processBmMirrorFreeRequest: {}, do nothing ...", bidibMessage);
    }

    protected void processBmAddrGetRangeRequest(BidibMessageInterface bidibMessage) {

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

                int detectorNumber = port.getId();
                List bidibAddresses = new ArrayList<>();
                List addresses = port.getAddresses();
                for (FeedbackAddressData addressData : addresses) {
                    final EnrailmentDirectionEnum enrailmentDirection = addressData.getType();
                    AddressTypeEnum addressType = null;
                    switch (enrailmentDirection) {
                        case LOCOMOTIVE_LEFT:
                        case LOCOMOTIVE_RIGHT:
                            addressType = AddressTypeEnum.LOCOMOTIVE_FORWARD;
                            break;
                        case BASIC_ACCESSORY:
                            addressType = AddressTypeEnum.ACCESSORY;
                            break;
                        case EXTENDED_ACCESSORY:
                            addressType = AddressTypeEnum.EXTENDED_ACCESSORY;
                            break;
                        default:
                            break;
                    }
                    AddressData bidibAddress = new AddressData(addressData.getAddress(), addressType);
                    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);
        }
    }

    @Override
    protected byte[] processBmGetConfidenceRequest(BidibMessageInterface 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;
    }

    @Override
    protected byte[] processLcConfigXSetRequest(BidibMessageInterface 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) {

                    Map> currentPortConfig = port.getPortConfigX();

                    // the problem here is that the BIDIB_PCFG_RECONFIG overwrites the supported port types
                    LcConfigX lcConfigX = lcConfigXSetMessage.getLcConfigX(messageLogger);
                    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());

                    for (Entry> entry : lcConfigX.getPortConfig().entrySet()) {
                        Byte key = entry.getKey();
                        if (currentPortConfig.containsKey(key)) {
                            currentPortConfig.remove(key);
                        }
                        currentPortConfig.put(key, entry.getValue());
                    }

                    port.setPortConfigX(currentPortConfig);

                    lcConfigX.getPortConfig().clear();
                    lcConfigX.getPortConfig().putAll(currentPortConfig);

                    // TODO remove this test
                    if (outputNumber == 5) {
                        LOGGER.warn("Change the content to signal an error ...");
                        lcConfigX.getPortConfig().put(BidibLibrary.BIDIB_PCFG_NONE, new BytePortConfigValue((byte) 12));
                    }

                    byte[] content = LcConfigX.getCodedPortConfig(null, lcConfigX, getPortModel());
                    LOGGER.info("Prepared content: {}", ByteUtils.bytesToHex(content));

                    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;
    }

    @Override
    protected byte[] processLcConfigXGetRequest(BidibMessageInterface 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 < servoPortCount) { // 4 or 8 servo ports
                        values
                            .put(BidibLibrary.BIDIB_PCFG_RECONFIG,
                                new ReconfigPortConfigValue(Integer.valueOf(0x000402)));
                    }
                    else if (outputNumber >= 4 && outputNumber < (servoPortCount + 16)) { // 16 power ports
                        values.putAll(port.getPortConfigX());
                    }
                    else { // GPIO are all input ports
                        values
                            .put(BidibLibrary.BIDIB_PCFG_RECONFIG,
                                new ReconfigPortConfigValue(Integer.valueOf(0x80010F)));

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

                    // // 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(),
                            LcConfigX.getCodedPortConfig(null, 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;
    }

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

        if (isPortFlatModelAvailable()) {
            LcOutputType outputType = LcOutputType.SWITCHPORT;

            Map> values = new LinkedHashMap<>();

            try {
                for (GenericPort port : genericPorts.values()) {
                    int portNumber = port.getPortNumber();
                    LOGGER.info("Prepare lcConfigXResponse for port number: {}", portNumber);
                    values.clear();

                    values.putAll(port.getPortConfigX());

                    // 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(),
                            LcConfigX.getCodedPortConfig(null, 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);
        }
    }

    @Override
    protected byte[] processLcOutputRequest(BidibMessageInterface bidibMessage) {
        LOGGER.info("Process the LcOutput request: {}", bidibMessage);

        byte[] response = null;

        if (getFlatPortModelPortCount() > 0) {

            try {
                LcOutputMessage lcOutputMessage = (LcOutputMessage) bidibMessage;
                LcOutputType outputType = lcOutputMessage.getOutputType(getPortModel());
                int outputNumber = lcOutputMessage.getOutputNumber(getPortModel());
                byte outputStatus = lcOutputMessage.getOutputStatus();

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

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

                if (port != null) {

                    LcStatResponse lcStatResponse = null;
                    if (port.isMatchingPortType(LcOutputType.SERVOPORT)
                        || port.isMatchingPortType(LcOutputType.BACKLIGHTPORT)) {
                        port.setPortValue(ByteUtils.getInt(outputStatus));
                    }
                    else {
                        port.setPortStatus(outputStatus);
                    }

                    lcStatResponse =
                        new LcStatResponse(bidibMessage.getAddr(), getNextSendNum(), bidibPort,
                            lcOutputMessage.getOutputStatus());
                    response = lcStatResponse.getContent();
                }
                else {
                    LOGGER.warn("No port available with portNumber: {}", outputNumber);
                    LcNotAvailableResponse lcNotAvailableResponse =
                        new LcNotAvailableResponse(bidibMessage.getAddr(), getNextSendNum(), bidibPort);
                    response = lcNotAvailableResponse.getContent();
                }

                if (port != null) {
                    switch (outputType) {
                        case LIGHTPORT:
                            publishLightPortChange(port);
                            break;
                        case SWITCHPORT:
                            publishSwitchPortChange(port);
                            break;
                        case SERVOPORT:
                            publishServoPortChange(port);
                            break;
                        default:
                            break;
                    }
                }
            }
            catch (ProtocolException ex) {
                LOGGER.warn("Create LcStat response failed.", ex);
            }

        }
        else {
            response = super.processLcOutputRequest(bidibMessage);
        }
        return response;
    }

    @Override
    protected byte[] processLcPortQueryRequest(BidibMessageInterface bidibMessage) {

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

        if (isPortFlatModelAvailable()) {

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

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

                byte portState = 0;
                if (port != null) {
                    if (port.isMatchingPortType(LcOutputType.SERVOPORT)
                        || port.isMatchingPortType(LcOutputType.BACKLIGHTPORT)) {
                        portState = ByteUtils.getLowByte(port.getPortValue());
                    }
                    else {
                        portState = port.getPortStatus();
                    }
                }
                else {
                    LOGGER.warn("No port available with portNumber: {}", outputNumber);
                }

                BidibPort bidibPort = prepareBidibPort(getPortModel(), outputType, 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.processLcPortQueryRequest(bidibMessage);
        }
        return response;
    }

    @Override
    protected byte[] processLcPortQueryAllRequest(BidibMessageInterface bidibMessage) {
        LOGGER.info("Process the PortQueryAll request: {}", bidibMessage);

        if (getFlatPortModelPortCount() > 0) {
            byte[] response = null;
            try {
                LcPortQueryAllMessage portQueryAllMessage = (LcPortQueryAllMessage) bidibMessage;
                int portRangeFrom = portQueryAllMessage.getPortRangeFrom(getPortModel());
                int portRangeTo = portQueryAllMessage.getPortRangeTo(getPortModel());

                int portTypeMask = portQueryAllMessage.getPortTypeMask();

                LOGGER
                    .info("Query all port states, portRangeFrom: {}, portRangeTo: {}, portModel: {}, portTypeMask: {}",
                        portRangeFrom, portRangeTo, getPortModel(), portTypeMask);

                for (GenericPort genericPort : genericPorts.values()) {
                    LcOutputType currentPortType = genericPort.getCurrentPortType();

                    if (PortConfigUtils.isSupportsPortType(currentPortType, portTypeMask)
                        && (genericPort.getPortNumber() >= portRangeFrom
                            && genericPort.getPortNumber() < portRangeTo)) {
                        try {
                            // byte portStatus = genericPort.getPortStatus();
                            byte portStatus = 0;
                            if (genericPort.isMatchingPortType(LcOutputType.SERVOPORT)
                                || genericPort.isMatchingPortType(LcOutputType.BACKLIGHTPORT)) {
                                portStatus = ByteUtils.getLowByte(genericPort.getPortValue());
                            }
                            else {
                                portStatus = genericPort.getPortStatus();
                            }
                            publishPortState(bidibMessage.getAddr(), currentPortType, genericPort.getPortNumber(),
                                portStatus);
                        }
                        catch (Exception ex) {
                            LOGGER.warn("Publish port state failed for port: {}", genericPort, ex);
                        }
                    }
                    else {
                        LOGGER.info("Skip current port that is out of port range or wrong port type: {}", genericPort);
                    }
                }

                LOGGER.info("Send the terminating LC_NA message.");
                publishLcNaResponse(bidibMessage.getAddr());

            }
            catch (ProtocolException ex) {
                LOGGER.warn("Create LcStat response failed.", ex);
            }

            return response;
        }
        else {
            LOGGER
                .info(
                    "The OneControlSimulator is configured as type-oriented port model! Delegate evaluation to LightControlSimulator.");
            return super.processLcPortQueryAllRequest(bidibMessage);
        }
    }

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

        if (isPortFlatModelAvailable()) {
            byte keyState = 0;
            GenericSimulationPort port = null;
            try {
                LcKeyMessage lcKeyMessage = (LcKeyMessage) bidibMessage;
                int portNumber = lcKeyMessage.getBidibPort().getPortNumber(PortModelEnum.type);

                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 Timer simulationTimer;

    private List accessoryResponseList = new ArrayList<>();

    @Override
    protected byte[] processAccessorySetRequest(final BidibMessageInterface bidibMessage) {
        LOGGER.info("Process the AccessorySet request: {}", bidibMessage);
        byte[] response = null;

        try {
            AccessorySetMessage accessorySetMessage = (AccessorySetMessage) bidibMessage;
            int accessoryNumber = accessorySetMessage.getAccessoryNumber();
            int aspect = accessorySetMessage.getAspect();

            byte[] value = new byte[] { 0, 0, 0 };
            // byte[] value = new byte[] { 2, 1, 20 };

            if (accessoryNumber == 1 && aspect == 1) {
                LOGGER.warn("Adding simulated error to accessory state response");

                value = new byte[] { 2, 1, 20 };

                // add the remaining response values
                accessoryResponseList.add(accessoryNumber + "," + aspect + ",2,128,7");
                accessoryResponseList.add(accessoryNumber + ",255,2,129,7");
                accessoryResponseList.add(accessoryNumber + ",255,2,0,0");

                simulationTimer = new Timer(1500, new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {

                        if (!accessoryResponseList.isEmpty()) {
                            String accessoryResponse = accessoryResponseList.remove(0);
                            if (StringUtils.isNotBlank(accessoryResponse)) {
                                LOGGER.info("Send response: {}", accessoryResponse);
                                // parse
                                String[] parts = accessoryResponse.split(",");
                                byte[] value = new byte[parts.length];
                                int index = 0;
                                for (String part : parts) {
                                    int val = Integer.parseInt(part);
                                    value[index] = ByteUtils.getLowByte(val);
                                    index++;
                                }

                                try {
                                    AccessoryStateResponse accessoryStateResponse =
                                        new AccessoryStateResponse(bidibMessage.getAddr(), getNextSendNum(),
                                            /* accessoryNumber */value[0], /* aspect */value[1],
                                            ByteUtils.subArray(value, 2));
                                    byte[] response = accessoryStateResponse.getContent();
                                    LOGGER.info("Prepared accessoryStateResponse: {}", accessoryStateResponse);
                                    sendSpontanousResponse(response);
                                }
                                catch (ProtocolException ex) {
                                    LOGGER.warn("Create AccessoryState response failed.", ex);
                                }
                            }
                        }

                        if (accessoryResponseList.isEmpty()) {
                            LOGGER.info("No more entries in accessoryResponseList. Stop and release timer.");
                            simulationTimer.stop();
                            simulationTimer = null;
                        }
                    }
                });
                simulationTimer.start();
            }

            // send accessory state response
            AccessoryStateResponse accessoryStateResponse =
                new AccessoryStateResponse(bidibMessage.getAddr(), getNextSendNum(),
                    ByteUtils.getLowByte(accessoryNumber), ByteUtils.getLowByte(aspect), value);
            response = accessoryStateResponse.getContent();

        }
        catch (ProtocolException ex) {
            LOGGER.warn("Create AccessoryState response failed.", ex);
        }
        return response;
    }

    // //////

    private void publishLightPortChange(GenericPort port) {
        LightPortStatus status = LightPortStatus.valueOf(LightPortEnum.valueOf(port.getPortStatus()));

        LOGGER.info("The lightport status has changed, notify the listeners, nodeAddress: {}", nodeAddress);
        EventBus.publish(new LightPortStatusEvent(NodeUtils.formatAddress(nodeAddress), port.getPortNumber(), status));
    }

    private void publishSwitchPortChange(GenericPort port) {
        SwitchPortStatus status = SwitchPortStatus.valueOf(SwitchPortEnum.valueOf(port.getPortStatus()));

        LOGGER.info("The switchport status has changed, notify the listeners, nodeAddress: {}", nodeAddress);
        EventBus.publish(new SwitchPortStatusEvent(NodeUtils.formatAddress(nodeAddress), port.getPortNumber(), status));
    }

    private void publishServoPortChange(GenericPort port) {
        int value = port.getPortValue();

        LOGGER.info("The servoport status has changed, notify the listeners, nodeAddress: {}", nodeAddress);
        EventBus.publish(new ServoPortStatusEvent(NodeUtils.formatAddress(nodeAddress), port.getPortNumber(), value));
    }

    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(NodeUtils.formatAddress(nodeAddress), port.getPortNumber(), status));
    }

    @Override
    protected void changeInputPortStatus(int portNum) {
        LOGGER.info("Change the port status of input port with portNum: {}", portNum);

        GenericSimulationPort port = null;

        if (isPortFlatModelAvailable()) {
            try {
                port = genericPorts.get(Integer.valueOf(portNum));
            }
            catch (Exception ex) {
                LOGGER.warn("Get input port failed.", ex);
            }

            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);
            }

        }
        else {
            super.changeInputPortStatus(portNum);
        }
    }

    private void publishFeedbackPortChange(Port port) {
        FeedbackPort feedbackPort = (FeedbackPort) port;
        FeedbackPortStatus status = feedbackPort.getStatus();

        LOGGER.info("The feedbackport status has changed, notify the listeners, nodeAddress: {}", nodeAddress);
        EventBus.publish(new FeedbackPortStatusEvent(NodeUtils.formatAddress(nodeAddress), port.getId(), status));
    }

    @Override
    public void queryStatus(final Class portClass) {

        if (FeedbackPort.class.equals(portClass)) {
            for (FeedbackPort feedbackPort : feedbackPorts.values()) {
                publishFeedbackPortChange(feedbackPort);
            }

            // publish the confidence
            publishFeedbackConfidenceStatusEvent(statusValid.get(), statusFreeze.get(), statusSignal.get());
        }
        else {

            if (isPortFlatModelAvailable()) {

                for (GenericSimulationPort port : genericPorts.values()) {
                    if (portClass == InputPort.class && port.isMatchingPortType(LcOutputType.INPUTPORT)) {
                        publishInputPortChange(port);
                    }
                    else if (portClass == SwitchPort.class && port.isMatchingPortType(LcOutputType.SWITCHPORT)) {
                        publishSwitchPortChange(port);
                    }
                    else if (portClass == LightPort.class && port.isMatchingPortType(LcOutputType.LIGHTPORT)) {
                        publishLightPortChange(port);
                    }
                    else {
                        LOGGER.warn("Query port status for unsupported port class: {}", portClass);
                    }
                }
            }
            else {
                super.queryStatus(portClass);
            }
        }
    }

    @Override
    @EventSubscriber(eventClass = FeedbackConfidenceSetEvent.class)
    public void feedbackConfidenceSetEvent(FeedbackConfidenceSetEvent feedbackConfidenceEvent) {
        String nodeAddress = feedbackConfidenceEvent.getNodeAddr();
        LOGGER.info("The change of the feedback confidence was requested, nodeAddress: {}", nodeAddress);

        // check if the node is addressed
        if (!isAddressEqual(nodeAddress)) {
            LOGGER.trace("Another node is addressed.");
            return;
        }

        statusValid.set(feedbackConfidenceEvent.getValid());
        statusFreeze.set(feedbackConfidenceEvent.getFreeze());
        statusSignal.set(feedbackConfidenceEvent.getSignal());

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

        try {
            FeedbackConfidenceResponse feedbackConfidenceResponse =
                new FeedbackConfidenceResponse(this.nodeAddress, getNextSendNum(), valid, freeze, signal);
            LOGGER.info("Prepared feedbackConfidenceResponse: {}", feedbackConfidenceResponse);
            sendSpontanousResponse(feedbackConfidenceResponse.getContent());
        }
        catch (ProtocolException ex) {
            LOGGER.warn("Send feedbackConfidenceResponse failed.", ex);
        }

        publishFeedbackConfidenceStatusEvent(statusValid.get(), statusFreeze.get(), statusSignal.get());
    }

    private void publishFeedbackConfidenceStatusEvent(boolean valid, boolean freeze, boolean signal) {

        LOGGER
            .info("The feedbackport confidence status has changed, notify the listeners, nodeAddress: {}", nodeAddress);
        EventBus
            .publish(new FeedbackConfidenceStatusEvent(NodeUtils.formatAddress(nodeAddress), valid, freeze, signal));
    }

    @EventSubscriber(eventClass = FeedbackPortSetStatusEvent.class)
    public void feedbackPortSetStatus(FeedbackPortSetStatusEvent setStatusEvent) {
        LOGGER.info("The change of the feedback port was requested, setStatusEvent: {}", setStatusEvent);
        String nodeAddress = setStatusEvent.getNodeAddr();

        // check if the node is addressed
        if (!isAddressEqual(nodeAddress)) {
            LOGGER.trace("Another node is addressed.");
            return;
        }

        int portNum = setStatusEvent.getPortNum();
        try {
            changeFeedbackPortStatus(portNum);
        }
        catch (ProtocolException ex) {
            LOGGER.warn("Publish feedback status failed.", ex);
        }
    }

    private int timestamp;

    private int getTimestamp() {
        timestamp += 10;
        if (timestamp > 65000) {
            timestamp = 0;
        }
        return timestamp;
    }

    private boolean hasTimestampFeature() {
        Feature feature = Feature.findFeature(features, BidibLibrary.FEATURE_BM_TIMESTAMP_ON);

        return (feature != null && feature.getValue() > 0);
    }

    protected void changeFeedbackPortStatus(int portNum) throws ProtocolException {

        FeedbackPort port = feedbackPorts.get(portNum);
        if (port != null) {
            BidibMessage response = null;

            LOGGER.info("Publish status report for port: {}", port);

            switch (port.getStatus()) {
                case FREE:
                    port.setStatus(FeedbackPortStatus.OCCUPIED);
                    if (hasTimestampFeature()) {
                        response =
                            new FeedbackOccupiedResponse(getNodeAddress(), getNextSendNum(), portNum, getTimestamp());
                    }
                    else {
                        response = new FeedbackOccupiedResponse(getNodeAddress(), getNextSendNum(), portNum);
                    }

                    break;
                default:
                    port.setStatus(FeedbackPortStatus.FREE);

                    response = new FeedbackFreeResponse(getNodeAddress(), getNextSendNum(), portNum);
                    break;
            }

            sendSpontanousResponse(response.getContent());

            publishFeedbackPortChange(port);
        }
        else {
            LOGGER.warn("The requested feedback port is not available: {}", portNum);
        }
    }

    @Override
    public void setPortsConfig(FlatPortType flatPortType) {
        if (flatPortType == null) {
            return;
        }

        LOGGER.debug("Set the ports config: {}", flatPortType);

        if (CollectionUtils.isNotEmpty(flatPortType.getBACKLIGHTOrLIGHTOrINPUT())) {
            for (PortParamsType flatPortParamsType : flatPortType.getBACKLIGHTOrLIGHTOrINPUT()) {

                if (flatPortParamsType instanceof FlatInputPortType) {
                    // add input port
                    prepareInutPortFromConfig((FlatInputPortType) flatPortParamsType);
                }
                // else if (flatPortParamsType instanceof FlatLightPortType) {
                // // add light port
                // prepareLightPortFromConfig((FlatLightPortType) flatPortParamsType);
                // }
                // else if (flatPortParamsType instanceof FlatBacklightPortType) {
                // // add backlight port
                // prepareBacklightPortFromConfig((FlatBacklightPortType) flatPortParamsType);
                // }
                else if (flatPortParamsType instanceof FlatServoPortType) {
                    // add servo port
                    prepareServoPortFromConfig((FlatServoPortType) flatPortParamsType);
                }
                else if (flatPortParamsType instanceof FlatSwitchPortType) {
                    // add switch port
                    prepareSwitchPortFromConfig((FlatSwitchPortType) flatPortParamsType);
                }
                else {
                    LOGGER.warn("Unsupported flatPortParamsType detected: {}", flatPortParamsType);
                }
            }
        }

    }

    protected void prepareServoPortFromConfig(final FlatServoPortType servoPortType) {

        // overwrite configured ports

        int portNumber = servoPortType.getPortId();
        GenericSimulationPort servoPort = new GenericSimulationPort(portNumber);

        int portTypeMap = getPortTypeMap(servoPortType.getPortTypeMap());

        servoPort.setCurrentPortType(LcOutputType.SERVOPORT, portTypeMap);

        Map> portConfig = new LinkedHashMap<>();
        portConfig
            .put(BidibLibrary.BIDIB_PCFG_SERVO_SPEED,
                new BytePortConfigValue(ByteUtils.getLowByte(servoPortType.getSpeed())));
        portConfig
            .put(BidibLibrary.BIDIB_PCFG_SERVO_ADJ_L,
                new BytePortConfigValue(ByteUtils.getLowByte(servoPortType.getAdjustLow())));
        portConfig
            .put(BidibLibrary.BIDIB_PCFG_SERVO_ADJ_H,
                new BytePortConfigValue(ByteUtils.getLowByte(servoPortType.getAdjustHigh())));

        servoPort.setPortConfigX(portConfig);

        servoPort.setConfigStatus(PortConfigStatus.CONFIG_PASSED);

        servoPort.setPortValue(servoPortType.getValue());

        LOGGER.info("Add configured servo port: {}", servoPort);

        // add the configured port
        genericPorts.put(servoPort.getPortNumber(), servoPort);
    }

    protected void prepareSwitchPortFromConfig(final FlatSwitchPortType switchPortType) {

        // overwrite configured ports

        int portNumber = switchPortType.getPortId();
        GenericSimulationPort switchPort = new GenericSimulationPort(portNumber);

        LcOutputType lcOutputType = LcOutputType.SWITCHPORT;
        int portTypeMap = getPortTypeMap(switchPortType.getPortTypeMap());
        if (portNumber % 2 == 1) {
            // odd ports are not switchpair ports
            portTypeMap &= 0xFF7F;
        }
        else if (portNumber < 24) {
            lcOutputType = LcOutputType.SWITCHPAIRPORT;
        }

        switchPort.setCurrentPortType(lcOutputType, portTypeMap);

        Map> portConfig = new LinkedHashMap<>();
        portConfig
            .put(BidibLibrary.BIDIB_PCFG_TICKS,
                new BytePortConfigValue(ByteUtils.getLowByte(switchPortType.getTicks())));
        portConfig
            .put(BidibLibrary.BIDIB_PCFG_LOAD_TYPE,
                new BytePortConfigValue(ByteUtils.getLowByte(switchPortType.getLoadType())));
        // portConfig
        // .put(BidibLibrary.BIDIB_PCFG_SWITCH_CTRL,
        // new BytePortConfigValue(ByteUtils.getLowByte(switchPortType.getSwitchCtrl())));

        switchPort.setPortConfigX(portConfig);

        switchPort.setConfigStatus(PortConfigStatus.CONFIG_PASSED);

        switchPort.setPortStatus(SwitchPortStatus.ON.getType().getType());

        LOGGER.info("Add configured switch port: {}", switchPort);

        // add the configured port
        genericPorts.put(switchPort.getPortNumber(), switchPort);
    }

    protected void prepareInutPortFromConfig(final FlatInputPortType inputPortType) {

        int portNumber = inputPortType.getPortId();
        GenericSimulationPort inputPort = new GenericSimulationPort(portNumber);

        int portTypeMap = getPortTypeMap(inputPortType.getPortTypeMap());

        inputPort.setCurrentPortType(LcOutputType.INPUTPORT, portTypeMap);

        Map> portConfig = new LinkedHashMap<>();
        portConfig
            .put(BidibLibrary.BIDIB_PCFG_TICKS,
                new BytePortConfigValue(ByteUtils.getLowByte(inputPortType.getTicks())));
        portConfig
            .put(BidibLibrary.BIDIB_PCFG_INPUT_CTRL,
                new BytePortConfigValue(ByteUtils.getLowByte(inputPortType.getInputCtrl())));

        inputPort.setPortConfigX(portConfig);

        inputPort.setConfigStatus(PortConfigStatus.CONFIG_PASSED);

        inputPort.setPortStatus(InputPortStatus.ON.getType().getType());

        LOGGER.info("Add configured input port: {}", inputPort);

        // add the configured port
        genericPorts.put(inputPort.getPortNumber(), inputPort);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy