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