Skip to content

Instantly share code, notes, and snippets.

@splatch
Last active July 30, 2020 20:52
Embed
What would you like to do?
PLC4X 0.6 + ADS with an extra work to read symbol table.
#!/bin/python3
import pyads
from pyads import *
SENDER_AMS = '192.168.2.106.1.1'
PLC_IP = '192.168.2.221'
USERNAME = 'Administrator'
PASSWORD = '1'
ROUTE_NAME = 'RouteToMyPC'
HOSTNAME = '192.168.2.106'
PLC_AMS_ID = '192.168.2.221.1.1'
add_route_to_plc(SENDER_AMS, HOSTNAME, PLC_IP, USERNAME, PASSWORD, route_name=ROUTE_NAME)
with AdsDevice(amsTarget="192.168.2.221.1.1:801", amsSource='192.168.2.106.1.1:32455', targetIP="192.168.2.221") as device:
info = device.ReadDeviceInfo()
print(info)
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.apache.commons.codec.binary.Hex;
import org.apache.plc4x.java.PlcDriverManager;
import org.apache.plc4x.java.api.PlcConnection;
import org.apache.plc4x.java.api.messages.PlcReadRequest;
import org.apache.plc4x.java.api.messages.PlcReadResponse;
import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse;
import org.apache.plc4x.java.api.messages.PlcWriteRequest;
import org.apache.plc4x.java.api.messages.PlcWriteResponse;
import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
import org.apache.plc4x.java.api.types.PlcResponseCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static Logger logger = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) throws Exception {
List<String> addresses = Arrays.asList("MAIN.PLCBoolVar:BOOL");
String targetIp = "10.10.10.246";
//String targetIp = "192.168.2.221";
String targetAmsId = "192.168.2.221.1.1";
String targetAmsPort = "851";
// host ip address
String sourceAmsId = "192.168.2.106.1.1";
String sourceAmsPort = "30000";
String connectionString = "ads:tcp://" + targetIp + "/" + targetAmsId + ":" + targetAmsPort + "/" + sourceAmsId + ":" + sourceAmsPort;
// Establish a connection to the plc using the url provided as first argument
try (PlcConnection plcConnection = new PlcDriverManager().getConnection(connectionString)) {
System.err.println(plcConnection.getMetadata());
// // Check if this connection support reading of data.
// if (!plcConnection.getMetadata().canRead()) {
// logger.error("This connection doesn't support reading.");
// return;
// }
//
// PlcSubscriptionRequest subscriptionRequest = plcConnection.subscriptionRequestBuilder()
// .addChangeOfStateField("Input 001", "0xF021/0x0:BOOL").build();
//
// CompletableFuture<? extends PlcSubscriptionResponse> completableFuture = subscriptionRequest.execute();
// completableFuture.handleAsync((response, error) -> {
// if (error != null) {
// error.printStackTrace();
// return null;
// }
//
// for (PlcSubscriptionHandle handle : response.getSubscriptionHandles()) {
// System.out.println("Register event listener " + handle);
// handle.register(new Consumer<PlcSubscriptionEvent>() {
// @Override public void accept(PlcSubscriptionEvent plcSubscriptionEvent) {
// System.out.println("Zmiana stanu " + plcSubscriptionEvent.getFieldNames());
// }
// });
// }
// return true;
// });
PlcReadRequest.Builder readRequestBuilder = plcConnection.readRequestBuilder();
for (String address : addresses) {
readRequestBuilder.addItem(address, address).build();
}
CompletableFuture<? extends PlcReadResponse> response = readRequestBuilder.build().execute();
PlcReadResponse readResponse = response.get();
printResponse(readResponse);
String firstInput = addresses.get(0);
Boolean state = readResponse.getBoolean(firstInput);
state = state != true;
System.out.println("Set input state to " + state);
PlcWriteRequest.Builder writeRequestBuilder = plcConnection.writeRequestBuilder();
writeRequestBuilder.addItem(firstInput, firstInput, state).build();
CompletableFuture<? extends PlcWriteResponse> writeResponse = writeRequestBuilder.build().execute();
//printWriteResponse(writeResponse.get());
response = readRequestBuilder.build().execute();
readResponse = response.get();
printResponse(readResponse);
// read symbols
System.err.println("Reading symbol info");
readRequestBuilder = plcConnection.readRequestBuilder();
PlcReadRequest request = readRequestBuilder.addItem("symbol", "0xf00f/0x0:BYTE[30]").build();
PlcReadResponse rsp = request.execute().get();
ByteBuffer buffer = toBuffer(rsp, "symbol");
System.err.println(Hex.encodeHexString(buffer.array()));
int symbolAnswerSize = buffer.getInt(4);
System.err.println("Len " + symbolAnswerSize);
request = plcConnection.readRequestBuilder().addItem("symbol", "0xf00b/0x0:BYTE[" + symbolAnswerSize + "]").build();
readResponse = request.execute().get();
buffer = toBuffer(readResponse, "symbol");
//System.err.println(Hex.encodeHex(buffer));
int index = 0;
int pos = 0;
while (buffer.remaining() > 0) {
int sectionLen = buffer.getInt();
System.err.println("Symbol " + index++ + ", data length: " + sectionLen + " " + buffer.position());
System.err.println("Index Group " + buffer.getInt());
System.err.println("Index Offset " + buffer.getInt());
System.err.println("Symbol size " + buffer.getInt());
System.err.println("Symbol type " + buffer.getInt());
System.err.println("Symbol ??? " + buffer.getInt());
short nameLength = (short) (buffer.getShort() + 1);
short typeLength = (short) (buffer.getShort() + 1);
short commentLength = (short) (buffer.getShort() + 1);
System.err.println("Name length " + nameLength);
System.err.println("Type length " + typeLength);
System.err.println("Comment length " + commentLength);
System.err.println("Name " + slice(buffer, nameLength));
System.err.println("Type " + slice(buffer, typeLength));
System.err.println("Comment " + slice(buffer, commentLength));
pos += sectionLen;
buffer.position(pos);
//break;
System.err.println("===");
}
}
}
private static String slice(ByteBuffer buffer, short length) {
byte[] arr = new byte[length];
buffer.get(arr);
return new String(arr, StandardCharsets.UTF_8);
}
private static ByteBuffer toBuffer(PlcReadResponse rsp, String fieldName) {
System.err.println(rsp.getFieldNames() + " " + rsp.getField(fieldName) + " " + rsp.getResponseCode(fieldName));
List<Short> symbols = (List<Short>) rsp.getObject(fieldName);
ByteBuffer buffer = ByteBuffer.allocate(symbols.size()).order(ByteOrder.LITTLE_ENDIAN);
for (Short symbol : symbols) {
byte byteValue = symbol.byteValue();
//System.err.println("data " + Hex.encodeHexString(new byte[] {byteValue}));
buffer.put(byteValue);
}
buffer.rewind();
return buffer;
}
private static void printResponse(PlcSubscriptionResponse plcSubscriptionResponse) {
for (PlcSubscriptionHandle subscriptionHandle : plcSubscriptionResponse.getSubscriptionHandles()) {
subscriptionHandle.register(e -> {
System.out.println(e);
});
}
}
private static void printResponse(PlcReadResponse response) {
System.out.println("Read response");
for (String fieldName : response.getFieldNames()) {
if (response.getResponseCode(fieldName) == PlcResponseCode.OK) {
int numValues = response.getNumberOfValues(fieldName);
// If it's just one element, output just one single line.
if (numValues == 1) {
System.out.println("Value[" + fieldName + "]: " + response.getObject(fieldName));
}
// If it's more than one element, output each in a single row.
else {
System.out.println("Value[" + fieldName + "]:");
for (int i = 0; i < numValues; i++) {
System.out.println(" - " + response.getObject(fieldName, i));
}
}
}
// Something went wrong, to output an error message instead.
else {
System.out.println("Error[" + fieldName + "]: " + response.getResponseCode(fieldName).name());
}
}
}
private static void printWriteResponse(PlcWriteResponse response) {
System.out.println("Write response");
for (String fieldName : response.getFieldNames()) {
System.out.println(fieldName + " " + response.getResponseCode(fieldName));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment