Search in sources :

Example 1 with DefaultPlcSubscriptionField

use of org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField in project plc4x by apache.

the class FirmataDriverContext method processSubscriptionRequest.

public List<FirmataMessage> processSubscriptionRequest(PlcSubscriptionRequest subscriptionRequest) {
    // Convert the request into maps of bit sets.
    Map<Integer, PinMode> requestDigitalFieldPinModes = new HashMap<>();
    Map<Integer, PinMode> requestAnalogFieldPinModes = new HashMap<>();
    for (String fieldName : subscriptionRequest.getFieldNames()) {
        final PlcField field = subscriptionRequest.getField(fieldName);
        DefaultPlcSubscriptionField subscriptionField = (DefaultPlcSubscriptionField) field;
        if (subscriptionField.getPlcField() instanceof FirmataFieldDigital) {
            FirmataFieldDigital fieldDigital = (FirmataFieldDigital) subscriptionField.getPlcField();
            PinMode fieldPinMode = (fieldDigital.getPinMode() != null) ? fieldDigital.getPinMode() : PinMode.PinModeInput;
            if (!(fieldPinMode.equals(PinMode.PinModeInput) || fieldPinMode.equals(PinMode.PinModePullup))) {
                throw new PlcInvalidFieldException("Subscription field must be of type 'INPUT' (default) or 'PULLUP'");
            }
            for (int pin = fieldDigital.getAddress(); pin < fieldDigital.getAddress() + fieldDigital.getNumberOfElements(); pin++) {
                requestDigitalFieldPinModes.put(pin, fieldPinMode);
            }
        } else if (subscriptionField.getPlcField() instanceof FirmataFieldAnalog) {
            FirmataFieldAnalog fieldAnalog = (FirmataFieldAnalog) subscriptionField.getPlcField();
            for (int pin = fieldAnalog.getAddress(); pin < fieldAnalog.getAddress() + fieldAnalog.getNumberOfElements(); pin++) {
                requestAnalogFieldPinModes.put(pin, PinMode.PinModeInput);
            }
        } else {
            throw new PlcRuntimeException("Unsupported field type " + field.getClass().getSimpleName());
        }
    }
    // If a requested digital pin is already subscribed, blank this out
    for (Map.Entry<Integer, PinMode> entry : requestDigitalFieldPinModes.entrySet()) {
        int pin = entry.getKey();
        PinMode pinMode = entry.getValue();
        if (digitalPins.containsKey(pin)) {
            if (!digitalPins.get(pin).equals(pinMode)) {
                throw new PlcInvalidFieldException(String.format("Error setting digital pin to mode %s, pin is already set to mode %s", pinMode.toString(), digitalPins.get(pin).toString()));
            } else {
                requestDigitalFieldPinModes.remove(pin);
            }
        }
    }
    // If a requested analog pin is already subscribed, blank this out
    for (Map.Entry<Integer, PinMode> entry : requestAnalogFieldPinModes.entrySet()) {
        int pin = entry.getKey();
        if (analogPins.containsKey(pin)) {
            requestAnalogFieldPinModes.remove(pin);
        }
    }
    // Remember the subscription itself.
    subscriptions.add(subscriptionRequest);
    // Create a list of messages that need to be sent to achieve the desired subscriptions.
    List<FirmataMessage> messages = new LinkedList<>();
    for (Map.Entry<Integer, PinMode> entry : requestDigitalFieldPinModes.entrySet()) {
        int pin = entry.getKey();
        PinMode pinMode = entry.getValue();
        // Digital pins can be input and output, so first we have to set it to "input"
        messages.add(new FirmataMessageCommand(new FirmataCommandSetPinMode((byte) pin, pinMode, false), false));
        // And then tell the remote to send change of state information.
        messages.add(new FirmataMessageSubscribeDigitalPinValue((byte) pin, true, false));
    }
    for (Map.Entry<Integer, PinMode> entry : requestAnalogFieldPinModes.entrySet()) {
        int pin = entry.getKey();
        // Tell the remote to send change of state information for this analog pin.
        messages.add(new FirmataMessageSubscribeAnalogPinValue((byte) pin, true, false));
    }
    return messages;
}
Also used : PlcRuntimeException(org.apache.plc4x.java.api.exceptions.PlcRuntimeException) PlcField(org.apache.plc4x.java.api.model.PlcField) DefaultPlcSubscriptionField(org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField) PlcInvalidFieldException(org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException) FirmataFieldDigital(org.apache.plc4x.java.firmata.readwrite.field.FirmataFieldDigital) FirmataFieldAnalog(org.apache.plc4x.java.firmata.readwrite.field.FirmataFieldAnalog)

Example 2 with DefaultPlcSubscriptionField

use of org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField in project plc4x by apache.

the class OpcuaProtocolLogic method subscribe.

@Override
public CompletableFuture<PlcSubscriptionResponse> subscribe(PlcSubscriptionRequest subscriptionRequest) {
    return CompletableFuture.supplyAsync(() -> {
        Map<String, ResponseItem<PlcSubscriptionHandle>> values = new HashMap<>();
        long subscriptionId;
        ArrayList<String> fields = new ArrayList<>(subscriptionRequest.getFieldNames());
        long cycleTime = (subscriptionRequest.getField(fields.get(0))).getDuration().orElse(Duration.ofMillis(1000)).toMillis();
        try {
            CompletableFuture<CreateSubscriptionResponse> subscription = onSubscribeCreateSubscription(cycleTime);
            CreateSubscriptionResponse response = subscription.get(SecureChannel.REQUEST_TIMEOUT_LONG, TimeUnit.MILLISECONDS);
            subscriptionId = response.getSubscriptionId();
            subscriptions.put(subscriptionId, new OpcuaSubscriptionHandle(context, this, channel, subscriptionRequest, subscriptionId, cycleTime));
        } catch (Exception e) {
            throw new PlcRuntimeException("Unable to subscribe because of: " + e.getMessage());
        }
        for (String fieldName : subscriptionRequest.getFieldNames()) {
            final DefaultPlcSubscriptionField fieldDefaultPlcSubscription = (DefaultPlcSubscriptionField) subscriptionRequest.getField(fieldName);
            if (!(fieldDefaultPlcSubscription.getPlcField() instanceof OpcuaField)) {
                values.put(fieldName, new ResponseItem<>(PlcResponseCode.INVALID_ADDRESS, null));
            } else {
                values.put(fieldName, new ResponseItem<>(PlcResponseCode.OK, subscriptions.get(subscriptionId)));
            }
        }
        return new DefaultPlcSubscriptionResponse(subscriptionRequest, values);
    });
}
Also used : PlcRuntimeException(org.apache.plc4x.java.api.exceptions.PlcRuntimeException) TimeoutException(java.util.concurrent.TimeoutException) PlcRuntimeException(org.apache.plc4x.java.api.exceptions.PlcRuntimeException) DefaultPlcSubscriptionField(org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField) OpcuaField(org.apache.plc4x.java.opcua.field.OpcuaField) ResponseItem(org.apache.plc4x.java.spi.messages.utils.ResponseItem)

Example 3 with DefaultPlcSubscriptionField

use of org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField in project plc4x by apache.

the class OpcuaSubscriptionHandle method onSubscribeCreateMonitoredItemsRequest.

private CompletableFuture<CreateMonitoredItemsResponse> onSubscribeCreateMonitoredItemsRequest() {
    List<ExtensionObjectDefinition> requestList = new ArrayList<>(this.fieldNames.size());
    for (int i = 0; i < this.fieldNames.size(); i++) {
        final DefaultPlcSubscriptionField fieldDefaultPlcSubscription = (DefaultPlcSubscriptionField) subscriptionRequest.getField(fieldNames.get(i));
        NodeId idNode = generateNodeId((OpcuaField) fieldDefaultPlcSubscription.getPlcField());
        ReadValueId readValueId = new ReadValueId(idNode, 0xD, OpcuaProtocolLogic.NULL_STRING, new QualifiedName(0, OpcuaProtocolLogic.NULL_STRING));
        MonitoringMode monitoringMode;
        switch(fieldDefaultPlcSubscription.getPlcSubscriptionType()) {
            case CYCLIC:
                monitoringMode = MonitoringMode.monitoringModeSampling;
                break;
            case CHANGE_OF_STATE:
                monitoringMode = MonitoringMode.monitoringModeReporting;
                break;
            case EVENT:
                monitoringMode = MonitoringMode.monitoringModeReporting;
                break;
            default:
                monitoringMode = MonitoringMode.monitoringModeReporting;
        }
        long clientHandle = clientHandles.getAndIncrement();
        MonitoringParameters parameters = new MonitoringParameters(clientHandle, // sampling interval
        (double) cycleTime, // filter, null means use default
        OpcuaProtocolLogic.NULL_EXTENSION_OBJECT, // queue size
        1L, // discard oldest
        true);
        MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId, monitoringMode, parameters);
        requestList.add(request);
    }
    CompletableFuture<CreateMonitoredItemsResponse> future = new CompletableFuture<>();
    RequestHeader requestHeader = new RequestHeader(channel.getAuthenticationToken(), SecureChannel.getCurrentDateTime(), channel.getRequestHandle(), 0L, OpcuaProtocolLogic.NULL_STRING, SecureChannel.REQUEST_TIMEOUT_LONG, OpcuaProtocolLogic.NULL_EXTENSION_OBJECT);
    CreateMonitoredItemsRequest createMonitoredItemsRequest = new CreateMonitoredItemsRequest(requestHeader, subscriptionId, TimestampsToReturn.timestampsToReturnNeither, requestList.size(), requestList);
    ExpandedNodeId expandedNodeId = new // Namespace Uri Specified
    ExpandedNodeId(// Namespace Uri Specified
    false, // Server Index Specified
    false, new NodeIdFourByte((short) 0, Integer.parseInt(createMonitoredItemsRequest.getIdentifier())), null, null);
    ExtensionObject extObject = new ExtensionObject(expandedNodeId, null, createMonitoredItemsRequest, false);
    try {
        WriteBufferByteBased buffer = new WriteBufferByteBased(extObject.getLengthInBytes(), ByteOrder.LITTLE_ENDIAN);
        extObject.serialize(buffer);
        Consumer<byte[]> consumer = opcuaResponse -> {
            CreateMonitoredItemsResponse responseMessage = null;
            try {
                ExtensionObjectDefinition unknownExtensionObject = ExtensionObject.staticParse(new ReadBufferByteBased(opcuaResponse, ByteOrder.LITTLE_ENDIAN), false).getBody();
                if (unknownExtensionObject instanceof CreateMonitoredItemsResponse) {
                    responseMessage = (CreateMonitoredItemsResponse) unknownExtensionObject;
                } else {
                    ServiceFault serviceFault = (ServiceFault) unknownExtensionObject;
                    ResponseHeader header = (ResponseHeader) serviceFault.getResponseHeader();
                    LOGGER.error("Subscription ServiceFault returned from server with error code,  '{}'", header.getServiceResult().toString());
                    plcSubscriber.onDisconnect(context);
                }
            } catch (ParseException e) {
                LOGGER.error("Unable to parse the returned Subscription response");
                e.printStackTrace();
                plcSubscriber.onDisconnect(context);
            }
            for (MonitoredItemCreateResult result : responseMessage.getResults().toArray(new MonitoredItemCreateResult[0])) {
                if (OpcuaStatusCode.enumForValue(result.getStatusCode().getStatusCode()) != OpcuaStatusCode.Good) {
                    LOGGER.error("Invalid Field {}, subscription created without this field", fieldNames.get((int) result.getMonitoredItemId()));
                } else {
                    LOGGER.debug("Field {} was added to the subscription", fieldNames.get((int) result.getMonitoredItemId() - 1));
                }
            }
            future.complete(responseMessage);
        };
        Consumer<TimeoutException> timeout = e -> {
            LOGGER.info("Timeout while sending the Create Monitored Item Subscription Message");
            e.printStackTrace();
            plcSubscriber.onDisconnect(context);
        };
        BiConsumer<OpcuaAPU, Throwable> error = (message, e) -> {
            LOGGER.info("Error while sending the Create Monitored Item Subscription Message");
            e.printStackTrace();
            plcSubscriber.onDisconnect(context);
        };
        channel.submit(context, timeout, error, consumer, buffer);
    } catch (SerializationException e) {
        LOGGER.info("Unable to serialize the Create Monitored Item Subscription Message");
        e.printStackTrace();
        plcSubscriber.onDisconnect(context);
    }
    return future;
}
Also used : PlcSubscriptionEvent(org.apache.plc4x.java.api.messages.PlcSubscriptionEvent) java.util(java.util) Logger(org.slf4j.Logger) LoggerFactory(org.slf4j.LoggerFactory) PlcValue(org.apache.plc4x.java.api.value.PlcValue) TimeoutException(java.util.concurrent.TimeoutException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) DefaultPlcConsumerRegistration(org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration) CompletableFuture(java.util.concurrent.CompletableFuture) PlcConsumerRegistration(org.apache.plc4x.java.api.model.PlcConsumerRegistration) Instant(java.time.Instant) DefaultPlcSubscriptionHandle(org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionHandle) PlcSubscriptionRequest(org.apache.plc4x.java.api.messages.PlcSubscriptionRequest) org.apache.plc4x.java.spi.generation(org.apache.plc4x.java.spi.generation) Consumer(java.util.function.Consumer) AtomicLong(java.util.concurrent.atomic.AtomicLong) SecureChannel(org.apache.plc4x.java.opcua.context.SecureChannel) ConversationContext(org.apache.plc4x.java.spi.ConversationContext) DefaultPlcSubscriptionField(org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField) org.apache.plc4x.java.opcua.readwrite(org.apache.plc4x.java.opcua.readwrite) DefaultPlcSubscriptionEvent(org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionEvent) BiConsumer(java.util.function.BiConsumer) OpcuaField(org.apache.plc4x.java.opcua.field.OpcuaField) ResponseItem(org.apache.plc4x.java.spi.messages.utils.ResponseItem) DefaultPlcSubscriptionField(org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField) CompletableFuture(java.util.concurrent.CompletableFuture) TimeoutException(java.util.concurrent.TimeoutException)

Example 4 with DefaultPlcSubscriptionField

use of org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField in project plc4x by apache.

the class SimulatedDevice method addEventSubscription.

public void addEventSubscription(Consumer<PlcValue> consumer, PlcSubscriptionHandle handle, PlcSubscriptionField plcField) {
    LOGGER.debug("Adding event subscription: {}, {}, {}", consumer, handle, plcField);
    assert plcField instanceof DefaultPlcSubscriptionField;
    Future<?> submit = pool.submit(() -> {
        LOGGER.debug("WORKER: starting for {}, {}, {}", consumer, handle, plcField);
        while (!Thread.currentThread().isInterrupted()) {
            LOGGER.debug("WORKER: running for {}, {}, {}", consumer, handle, plcField);
            PlcField innerPlcField = ((DefaultPlcSubscriptionField) plcField).getPlcField();
            assert innerPlcField instanceof SimulatedField;
            PlcValue baseDefaultPlcValue = state.get(innerPlcField);
            if (baseDefaultPlcValue == null) {
                LOGGER.debug("WORKER: no value for {}, {}, {}", consumer, handle, plcField);
                continue;
            }
            LOGGER.debug("WORKER: accepting {} for {}, {}, {}", baseDefaultPlcValue, consumer, handle, plcField);
            consumer.accept(baseDefaultPlcValue);
            try {
                long sleepTime = Math.min(random.nextInt((int) TimeUnit.SECONDS.toNanos(5)), TimeUnit.MILLISECONDS.toNanos(500));
                LOGGER.debug("WORKER: sleeping {} milliseconds for {}, {}, {}", TimeUnit.NANOSECONDS.toMillis(sleepTime), consumer, handle, plcField);
                TimeUnit.NANOSECONDS.sleep(sleepTime);
            } catch (InterruptedException ignore) {
                Thread.currentThread().interrupt();
                LOGGER.debug("WORKER: got interrupted for {}, {}, {}", consumer, handle, plcField);
                return;
            }
        }
    });
    eventSubscriptions.put(handle, submit);
}
Also used : DefaultPlcSubscriptionField(org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField) PlcField(org.apache.plc4x.java.api.model.PlcField) SimulatedField(org.apache.plc4x.java.simulated.field.SimulatedField)

Example 5 with DefaultPlcSubscriptionField

use of org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField in project plc4x by apache.

the class SimulatedDevice method addCyclicSubscription.

public void addCyclicSubscription(Consumer<PlcValue> consumer, PlcSubscriptionHandle handle, PlcSubscriptionField plcField, Duration duration) {
    LOGGER.debug("Adding cyclic subscription: {}, {}, {}, {}", consumer, handle, plcField, duration);
    assert plcField instanceof DefaultPlcSubscriptionField;
    ScheduledFuture<?> scheduledFuture = scheduler.scheduleAtFixedRate(() -> {
        PlcField innerPlcField = ((DefaultPlcSubscriptionField) plcField).getPlcField();
        assert innerPlcField instanceof SimulatedField;
        PlcValue baseDefaultPlcValue = state.get(innerPlcField);
        if (baseDefaultPlcValue == null) {
            return;
        }
        consumer.accept(baseDefaultPlcValue);
    }, duration.toMillis(), duration.toMillis(), TimeUnit.MILLISECONDS);
    cyclicSubscriptions.put(handle, scheduledFuture);
}
Also used : DefaultPlcSubscriptionField(org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField) PlcField(org.apache.plc4x.java.api.model.PlcField) SimulatedField(org.apache.plc4x.java.simulated.field.SimulatedField)

Aggregations

DefaultPlcSubscriptionField (org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField)11 ResponseItem (org.apache.plc4x.java.spi.messages.utils.ResponseItem)7 PlcField (org.apache.plc4x.java.api.model.PlcField)6 CompletableFuture (java.util.concurrent.CompletableFuture)4 PlcRuntimeException (org.apache.plc4x.java.api.exceptions.PlcRuntimeException)4 java.util (java.util)3 TimeoutException (java.util.concurrent.TimeoutException)3 Consumer (java.util.function.Consumer)3 PlcValue (org.apache.plc4x.java.api.value.PlcValue)3 S7SubscriptionField (org.apache.plc4x.java.s7.readwrite.field.S7SubscriptionField)3 DefaultPlcSubscriptionResponse (org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionResponse)3 Instant (java.time.Instant)2 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)2 BiConsumer (java.util.function.BiConsumer)2 PlcProtocolException (org.apache.plc4x.java.api.exceptions.PlcProtocolException)2 PlcSubscriptionRequest (org.apache.plc4x.java.api.messages.PlcSubscriptionRequest)2 PlcConsumerRegistration (org.apache.plc4x.java.api.model.PlcConsumerRegistration)2 PlcSubscriptionHandle (org.apache.plc4x.java.api.model.PlcSubscriptionHandle)2 PlcResponseCode (org.apache.plc4x.java.api.types.PlcResponseCode)2 OpcuaField (org.apache.plc4x.java.opcua.field.OpcuaField)2