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

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

There is a newer version: 2.0.34
Show newest version
package org.bidib.wizard.simulation;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.collections4.MapUtils;
import org.bidib.jbidibc.messages.BidibLibrary;
import org.bidib.jbidibc.messages.BidibPort;
import org.bidib.jbidibc.messages.Feature;
import org.bidib.jbidibc.messages.LcConfigX;
import org.bidib.jbidibc.messages.enums.InputPortEnum;
import org.bidib.jbidibc.messages.enums.LcOutputType;
import org.bidib.jbidibc.messages.enums.SwitchPortEnum;
import org.bidib.jbidibc.messages.exception.ProtocolException;
import org.bidib.jbidibc.messages.message.BidibMessageInterface;
import org.bidib.jbidibc.messages.message.BidibRequestFactory;
import org.bidib.jbidibc.messages.message.LcConfigXGetAllMessage;
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.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.InputPortType;
import org.bidib.jbidibc.simulation.nodes.PortType;
import org.bidib.jbidibc.simulation.nodes.ServoPortType;
import org.bidib.jbidibc.simulation.nodes.SwitchPortType;
import org.bidib.wizard.model.ports.GenericPort;
import org.bidib.wizard.model.ports.InputPort;
import org.bidib.wizard.model.ports.ServoPort;
import org.bidib.wizard.model.ports.SwitchPort;
import org.bidib.wizard.model.status.InputPortStatus;
import org.bidib.wizard.model.status.SwitchPortStatus;
import org.bidib.wizard.simulation.events.InputPortSetStatusEvent;
import org.bidib.wizard.simulation.events.InputPortStatusEvent;
import org.bidib.wizard.simulation.events.PortConfigEvent;
import org.bidib.wizard.simulation.events.ServoPortStatusEvent;
import org.bidib.wizard.simulation.events.SwitchPortStatusEvent;
import org.bidib.wizard.simulation.ports.GenericSimulationPort;
import org.bidib.wizard.simulation.ports.PortListUtils;
import org.bushe.swing.event.EventBus;
import org.bushe.swing.event.annotation.EventSubscriber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@BidibNodeSimulators({ @BidibNodeSimulator(vid = "251", pid = "232") })
public class ReadyServo8Simulator extends LightControlSimulator implements SwitchingFunctionsNode {

    private static final Logger LOGGER = LoggerFactory.getLogger(ReadyServo8Simulator.class);

    private static final String SIMULATION_PANEL_CLASS =
        "org.bidib.wizard.simulation.client.view.panel.ReadyServo8Panel";

    private final Map genericPorts = new HashMap();

    public ReadyServo8Simulator(byte[] nodeAddress, long uniqueId, boolean autoAddFeature,
        SimulationBidibMessageProcessor messageReceiver, final BidibRequestFactory bidibRequestFactory) {
        super(nodeAddress, uniqueId, autoAddFeature, messageReceiver, bidibRequestFactory);
    }

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

    @Override
    public void postConstruct() {
        super.postConstruct();
        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);

            servoPortCount = 8;
            switchPortCount = 8; // GPIO port count
            inputPortOffset = switchPortCount;

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

                int mask = 0;
                // port 0..7 are servo ports
                if (portNumber >= 0 && portNumber < 8) {

                    port.setPortValue(120);

                    mask = 1 << BidibLibrary.BIDIB_PORTTYPE_SERVO;
                    port.setCurrentPortType(LcOutputType.SERVOPORT, mask);
                }
                else {
                    // GPIO input and switch port
                    port
                        .setPortStatus(portNumber % 2 == 0 ? InputPortStatus.ON.getType().getType()
                            : InputPortStatus.OFF.getType().getType());

                    mask = (1 << BidibLibrary.BIDIB_PORTTYPE_INPUT | 1 << BidibLibrary.BIDIB_PORTTYPE_SWITCH);
                    port.setCurrentPortType(LcOutputType.INPUTPORT, mask);
                }

                LOGGER.info("Register genericPort, portNumber: {}, port: {}", portNumber, port);
                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 prepareFeatures() {
        LOGGER.info("Prepare the features.");
        super.prepareFeatures();
    }

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

        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(200)));
                portConfig.put(BidibLibrary.BIDIB_PCFG_SERVO_SPEED, new BytePortConfigValue(ByteUtils.getLowByte(4)));
                portConfig.put(BidibLibrary.BIDIB_PCFG_SERVO_EXTRA, new BytePortConfigValue(ByteUtils.getLowByte(0)));
                portConfig.put(BidibLibrary.BIDIB_PCFG_MOVE_TYPE, new BytePortConfigValue(ByteUtils.getLowByte(0)));
                genericPort.setPortConfigX(portConfig);

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

            // this is a hack for the ReadyServo8
            LOGGER.info("Set the port type for GPIO ports, index: {}, switchPortCount: {}", index, switchPortCount);
            for (int portNum = 0; portNum < switchPortCount; portNum++) {
                GenericSimulationPort genericPort = genericPorts.get(portNum + index);
                int mask = (1 << BidibLibrary.BIDIB_PORTTYPE_SWITCH | 1 << BidibLibrary.BIDIB_PORTTYPE_INPUT);
                genericPort.setCurrentPortType(LcOutputType.SWITCHPORT, mask);

                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) 0x02)));
                portConfig.put(BidibLibrary.BIDIB_PCFG_TICKS, new BytePortConfigValue(Byte.valueOf((byte) 0x1E)));
                genericPort.setPortConfigX(portConfig);
            }
        }
    }

    @Override
    public void stop() {
        super.stop();
    }

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

        byte[] response = null;
        switch (ByteUtils.getInt(bidibMessage.getType())) {
            case BidibLibrary.MSG_LC_OUTPUT:
                response = processLcOutputRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_LC_CONFIG_GET:
                response = processLcConfigGetRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_LC_CONFIG_SET:
                response = processLcConfigSetRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_LC_KEY_QUERY:
                response = processLcKeyQueryRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_LC_PORT_QUERY:
                response = processLcPortQueryRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_LC_CONFIGX_SET:
                response = processLcConfigXSetRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_LC_CONFIGX_GET:
                response = processLcConfigXGetRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_LC_CONFIGX_GET_ALL:
                processLcConfigXGetAllRequest(bidibMessage);
                break;

            case BidibLibrary.MSG_LC_MACRO_HANDLE:
                response = processLcMacroHandleRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_LC_MACRO_PARA_GET:
                response = processLcMacroParaGetRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_LC_MACRO_PARA_SET:
                response = processLcMacroParaSetRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_LC_MACRO_GET:
                response = processLcMacroGetRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_LC_MACRO_SET:
                response = processLcMacroSetRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_ACCESSORY_SET:
                response = processAccessorySetRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_ACCESSORY_GET:
                response = processAccessoryGetRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_ACCESSORY_PARA_SET:
                response = processAccessoryParaSetRequest(bidibMessage);
                break;
            case BidibLibrary.MSG_ACCESSORY_PARA_GET:
                response = processAccessoryParaGetRequest(bidibMessage);
                break;

            default:
                response = super.prepareResponse(bidibMessage);
                break;
        }
        return response;
    }

    @Override
    protected byte[] processLcOutputRequest(BidibMessageInterface bidibMessage) {
        LOGGER.info("Process the LcOutput request: {}", bidibMessage);
        byte[] response = null;
        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 = 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 INPUTPORT:
                        publishInputPortChange(port);
                        break;
                    case SWITCHPORT:
                        publishSwitchPortChange(port);
                        break;
                    case SERVOPORT:
                        publishServoPortChange(port);
                        break;
                    default:
                        break;
                }
            }
        }
        catch (ProtocolException ex) {
            LOGGER.warn("Create LcStat response failed.", ex);
        }
        return response;
    }

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

    @Override
    protected byte[] processLcConfigXSetRequest(BidibMessageInterface bidibMessage) {
        LOGGER.info("Process the LcConfigXSet request: {}", bidibMessage);
        byte[] response = null;
        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 = BidibPort.prepareBidibPort(getPortModel(), outputType, outputNumber);

            boolean publishConfigChangeEvent = false;

            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) {
                    // Change of port type is requested, 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);

                        publishConfigChangeEvent = true;
                    }
                }

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

                switch (port.getCurrentPortType()) {
                    case INPUTPORT:
                        lcConfigX
                            .getPortConfig().put(BidibLibrary.BIDIB_PCFG_RECONFIG,
                                currentPortConfig.get(BidibLibrary.BIDIB_PCFG_RECONFIG));
                        lcConfigX
                            .getPortConfig().put(BidibLibrary.BIDIB_PCFG_INPUT_CTRL,
                                currentPortConfig.get(BidibLibrary.BIDIB_PCFG_INPUT_CTRL));

                        break;
                    case SWITCHPORT:
                        lcConfigX.getPortConfig().putAll(currentPortConfig);
                        lcConfigX.getPortConfig().remove(BidibLibrary.BIDIB_PCFG_INPUT_CTRL);
                        break;
                    default:
                        lcConfigX.getPortConfig().putAll(currentPortConfig);
                        break;
                }

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

                if (publishConfigChangeEvent) {
                    LOGGER.info("Publish the change of port type for port: {}", port);
                    publishPortConfigChange(port, port.getCurrentPortType());
                }
            }
            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);
        }
        return response;
    }

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

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

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

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

        try {
            LcConfigXGetAllMessage lcConfigXGetAllMessage = (LcConfigXGetAllMessage) bidibMessage;
            LcOutputType outputType = lcConfigXGetAllMessage.getPortTypeFrom(getPortModel());

            // TODO evaluate port type/range to

            Map> values = new HashMap<>();

            if (outputType != null) {
                LOGGER.info("Get all ports for output type: {}", outputType);

                byte[] response = null;

                switch (outputType) {
                    case SERVOPORT:
                        for (GenericSimulationPort servoPort : PortListUtils
                            .findPortsByType(genericPorts.values(), LcOutputType.SERVOPORT)) {
                            values.clear();

                            values.putAll(servoPort.getPortConfigX());

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

                            LcConfigXResponse lcConfigXResponse =
                                new LcConfigXResponse(bidibMessage.getAddr(), getNextSendNum(),
                                    LcConfigX.getCodedPortConfig(null, lcConfigX, getPortModel()));
                            response = lcConfigXResponse.getContent();

                            LOGGER.info("Prepared lcConfigXResponse: {}", ByteUtils.bytesToHex(response));
                            sendSpontanousResponse(response);
                            response = null;
                        }
                        break;
                    case SWITCHPORT:
                        for (GenericSimulationPort switchPort : PortListUtils
                            .findPortsByType(genericPorts.values(), LcOutputType.SWITCHPORT)) {
                            values.clear();

                            values.putAll(switchPort.getPortConfigX());
                            values.remove(BidibLibrary.BIDIB_PCFG_INPUT_CTRL);

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

                            LcConfigXResponse lcConfigXResponse =
                                new LcConfigXResponse(bidibMessage.getAddr(), getNextSendNum(),
                                    LcConfigX.getCodedPortConfig(null, lcConfigX, getPortModel()));
                            response = lcConfigXResponse.getContent();

                            LOGGER.info("Prepared lcConfigXResponse: {}", ByteUtils.bytesToHex(response));
                            sendSpontanousResponse(response);
                            response = null;
                        }
                        break;
                    case INPUTPORT:
                        for (GenericSimulationPort inputPort : PortListUtils
                            .findPortsByType(genericPorts.values(), LcOutputType.INPUTPORT)) {
                            values.clear();

                            // values.putAll(inputPort.getPortConfigX());
                            values
                                .put(BidibLibrary.BIDIB_PCFG_RECONFIG,
                                    inputPort.getPortConfigX().get(BidibLibrary.BIDIB_PCFG_RECONFIG));
                            values
                                .put(BidibLibrary.BIDIB_PCFG_INPUT_CTRL,
                                    inputPort.getPortConfigX().get(BidibLibrary.BIDIB_PCFG_INPUT_CTRL));

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

                            LcConfigXResponse lcConfigXResponse =
                                new LcConfigXResponse(bidibMessage.getAddr(), getNextSendNum(),
                                    LcConfigX.getCodedPortConfig(null, lcConfigX, getPortModel()));
                            response = lcConfigXResponse.getContent();

                            LOGGER.info("Prepared lcConfigXResponse: {}", ByteUtils.bytesToHex(response));
                            sendSpontanousResponse(response);
                            response = null;
                        }
                        break;
                    default:
                        LOGGER.warn("Unsupported port type requested: {}", outputType);
                        break;
                }
            }
            else {
                for (GenericPort port : genericPorts.values()) {
                    int portNumber = port.getPortNumber();
                    LOGGER.info("Prepare lcConfigXResponse for port number: {}", portNumber);
                    values.clear();

                    values.putAll(port.getPortConfigX());

                    switch (port.getCurrentPortType()) {
                        case INPUTPORT:
                            values.remove(BidibLibrary.BIDIB_PCFG_TICKS);
                            values.remove(BidibLibrary.BIDIB_PCFG_SWITCH_CTRL);
                            break;
                        case SWITCHPORT:
                            values.remove(BidibLibrary.BIDIB_PCFG_INPUT_CTRL);
                            break;
                        default:
                            break;
                    }

                    LOGGER.info("Return config of port: {}", port);
                    BidibPort 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);
        }

    }

    private void publishInputPortChange(GenericPort 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));
    }

    private void publishPortConfigChange(GenericPort port, LcOutputType signalledPortType) {

        LOGGER.info("The port config has changed, notify the listeners, nodeAddress: {}", nodeAddress);
        final PortConfigEvent portConfigEvent =
            new PortConfigEvent(NodeUtils.formatAddress(nodeAddress), port.getPortNumber(), signalledPortType, port);
        portConfigEvent.setEnabled(port.isMatchingPortType(signalledPortType));
        EventBus.publish(portConfigEvent);
    }

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

        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 = 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);
        }
        return response;
    }

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

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

    @Override
    public void queryStatus(Class portClass) {

        for (GenericSimulationPort port : genericPorts.values()) {
            if (portClass == InputPort.class) {
                if (port.isMatchingPortType(LcOutputType.INPUTPORT)) {
                    publishInputPortChange(port);
                }
                if (port.isSupportsInputPort()) {
                    publishPortConfigChange(port, LcOutputType.INPUTPORT);
                }
            }
            else if (portClass == SwitchPort.class) {
                if (port.isMatchingPortType(LcOutputType.SWITCHPORT)) {
                    publishSwitchPortChange(port);
                }
                if (port.isSupportsSwitchPort()) {
                    publishPortConfigChange(port, LcOutputType.SWITCHPORT);
                }
            }
            else if (portClass == ServoPort.class) {
                if (port.isMatchingPortType(LcOutputType.SERVOPORT)) {
                    publishServoPortChange(port);
                }
                if (port.isSupportsServoPort()) {
                    publishPortConfigChange(port, LcOutputType.SERVOPORT);
                }
            }
            else {
                LOGGER.warn("Query port status for unsupported port class: {}", portClass);
            }
        }
    }

    @Override
    public void setPortsConfig(PortType portType) {
        if (portType == null) {
            return;
        }

        LOGGER.info("Set the port config: {}", portType);
        if (portType instanceof SwitchPortType) {
            switchPortCount = portType.getCount();

            LOGGER.info("Set the number of switchPorts: {}", switchPortCount);
        }
        else if (portType instanceof InputPortType) {
            inputPortCount = portType.getCount();
            inputPortOffset = (portType.getOffset() != null ? portType.getOffset() : 0);
        }
        else if (portType instanceof ServoPortType) {
            servoPortCount = portType.getCount();
        }
    }

    @Override
    @EventSubscriber(eventClass = InputPortSetStatusEvent.class)
    public void inputPortSetStatus(InputPortSetStatusEvent setStatusEvent) {
        LOGGER.info("The change of the input port was requested.");
        String nodeAddress = setStatusEvent.getNodeAddr();

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

        int portNum = setStatusEvent.getPortNum();

        changeInputPortStatus(portNum);
    }

    @Override
    protected void changeInputPortStatus(int portNum) {

        GenericPort port =
            PortListUtils.findPortsByTypeAndPortNumber(genericPorts.values(), LcOutputType.INPUTPORT, portNum);
        if (port != null) {
            switch (InputPortStatus.valueOf(InputPortEnum.valueOf(port.getPortStatus()))) {
                case OFF:
                    port.setPortStatus(InputPortStatus.ON.getType().getType());
                    break;
                default:
                    port.setPortStatus(InputPortStatus.OFF.getType().getType());
                    break;
            }

            // prepare the request
            final LcPortQueryMessage lcPortQueryMessage =
                getBidibRequestFactory().createLcPortQuery(getPortModel(), LcOutputType.INPUTPORT, portNum);
            lcPortQueryMessage.setAddr(getNodeAddress());

            processRequest(lcPortQueryMessage);

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

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy