Skip to content

Commit

Permalink
feat(plc-simulator/bacnet): initial bacnet plc-simulator
Browse files Browse the repository at this point in the history
  • Loading branch information
sruehl committed Nov 3, 2022
1 parent a63ebe1 commit 37d8880
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 5 deletions.
19 changes: 17 additions & 2 deletions plc4j/utils/plc-simulator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
specific language governing permissions and limitations
under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

Expand Down Expand Up @@ -70,14 +71,19 @@
<!-- The Server is based on the same generated code as the client -->
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-driver-s7</artifactId>
<artifactId>plc4j-driver-bacnet</artifactId>
<version>0.11.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-driver-c-bus</artifactId>
<version>0.11.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-driver-s7</artifactId>
<version>0.11.0-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>org.apache.plc4x</groupId>
Expand Down Expand Up @@ -111,6 +117,15 @@
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
</dependency>


<dependency>
<groupId>org.slf4j</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ public static PlcSimulatorConfig plcSimulatorConfigFromArgs(String... args) thro
options.addOption("public", false, "listen on all interfaces (overrides host option)");
options.addOption("host", true, "the host interface");
options.addOption("s7Port", true, "changes the s7 port");
options.addOption("cBusPort", true, "changes the port");
options.addOption("cBusPort", true, "changes the C-Bus port");
options.addOption("bacnetPort", true, "changes the Bacnet port");

// Parse args
CommandLineParser parser = new DefaultParser();
Expand All @@ -163,6 +164,7 @@ public static PlcSimulatorConfig plcSimulatorConfigFromArgs(String... args) thro
}
config.s7Port = cmd.getOptionValue("s7port");
config.cBusPort = cmd.getOptionValue("cBusPort");
config.bacnetPort = cmd.getOptionValue("bacnetPort");

return config;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public class PlcSimulatorConfig {
String s7Port;
String cBusPort;

String bacnetPort;

public String getHost() {
return host;
}
Expand All @@ -35,4 +37,8 @@ public String getS7Port() {
public String getCBusPort() {
return cBusPort;
}

public String getBacnetPort() {
return bacnetPort;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.plc4x.simulator.server.bacnet;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DatagramPacketDecoder;
import io.netty.handler.codec.DatagramPacketEncoder;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.MessageToMessageEncoder;
import org.apache.plc4x.java.bacnetip.BacNetIpDriver;
import org.apache.plc4x.java.bacnetip.readwrite.BVLC;
import org.apache.plc4x.java.bacnetip.readwrite.BacnetConstants;
import org.apache.plc4x.java.cbus.CBusDriver;
import org.apache.plc4x.java.cbus.readwrite.CBusConstants;
import org.apache.plc4x.java.cbus.readwrite.CBusMessage;
import org.apache.plc4x.java.cbus.readwrite.CBusOptions;
import org.apache.plc4x.java.cbus.readwrite.RequestContext;
import org.apache.plc4x.java.spi.connection.GeneratedProtocolMessageCodec;
import org.apache.plc4x.java.spi.generation.ByteOrder;
import org.apache.plc4x.java.spi.generation.ReadBufferByteBased;
import org.apache.plc4x.java.spi.generation.WriteBufferByteBased;
import org.apache.plc4x.simulator.PlcSimulatorConfig;
import org.apache.plc4x.simulator.exceptions.SimulatorException;
import org.apache.plc4x.simulator.model.Context;
import org.apache.plc4x.simulator.server.ServerModule;
import org.apache.plc4x.simulator.server.bacnet.protocol.BacnetServerAdapter;

import java.util.List;

public class BacnetServerModule implements ServerModule {

private EventLoopGroup loopGroup;
private EventLoopGroup workerGroup;
private Context context;
private PlcSimulatorConfig config;

@Override
public String getName() {
return "Bacnet";
}

@Override
public void setConfig(PlcSimulatorConfig config) {
this.config = config;
}

@Override
public void setContext(Context context) {
this.context = context;
}

@Override
public void start() throws SimulatorException {
if (loopGroup != null) {
return;
}

try {
loopGroup = new NioEventLoopGroup();

Bootstrap bootstrap = new Bootstrap();
bootstrap.group(loopGroup)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new ChannelInitializer<NioDatagramChannel>() {
@Override
public void initChannel(NioDatagramChannel channel) {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new DatagramPacketDecoder(new MessageToMessageDecoder<ByteBuf>() {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
byte[] bytes = new byte[msg.readableBytes()];
msg.readBytes(bytes);
out.add(BVLC.staticParse(new ReadBufferByteBased(bytes)));
}
}));
pipeline.addLast(new DatagramPacketEncoder<>(new MessageToMessageEncoder<BVLC>() {
@Override
protected void encode(ChannelHandlerContext ctx, BVLC msg, List<Object> out) throws Exception {
WriteBufferByteBased writeBuffer = new WriteBufferByteBased(msg.getLengthInBytes());
msg.serialize(writeBuffer);
out.add(writeBuffer.getBytes());
}
}));
pipeline.addLast(new BacnetServerAdapter(context));
}
});

int port = BacnetConstants.BACNETUDPDEFAULTPORT;
if (config.getCBusPort() != null) {
port = Integer.parseInt(config.getCBusPort());
}
String host = config.getHost();
if (host != null) {
bootstrap.bind(host, port).sync();
} else {
bootstrap.bind(port).sync();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new SimulatorException(e);
}
}

@Override
public void stop() {
if (workerGroup == null) {
return;
}

workerGroup.shutdownGracefully();
loopGroup.shutdownGracefully();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.plc4x.simulator.server.bacnet.protocol;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.plc4x.java.bacnetip.readwrite.BVLC;
import org.apache.plc4x.java.cbus.readwrite.*;
import org.apache.plc4x.simulator.model.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BacnetServerAdapter extends ChannelInboundHandlerAdapter {

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

private Context context;

public BacnetServerAdapter(Context context) {
LOGGER.info("Creating adapter with context {}", context);
}


@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
}

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (!(msg instanceof BVLC)) {
return;
}
// TODO: implement me
System.out.println(msg);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ public void initChannel(SocketChannel channel) {
new CBusDriver.CorruptPackageCleaner()));
pipeline.addLast(new CBusServerAdapter(context));
}
}).option(ChannelOption.SO_BACKLOG, 128)
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);

int port = CBusConstants.CBUSTCPDEFAULTPORT;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
# under the License.
#
org.apache.plc4x.simulator.server.s7.S7ServerModule
org.apache.plc4x.simulator.server.cbus.CBusServerModule
org.apache.plc4x.simulator.server.cbus.CBusServerModule
org.apache.plc4x.simulator.server.bacnet.BacnetServerModule

0 comments on commit 37d8880

Please sign in to comment.