Giter Club home page Giter Club logo

modbus's People

Contributors

buger-od-ua avatar kevinherron avatar mrksngl avatar vbnetvbnet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

modbus's Issues

com.digitalpetri.modbus.ModbusTimeoutException: request timed out after 6000ms milliseconds.

the program throw error :

com.digitalpetri.modbus.ModbusTimeoutException: request timed out after 6000ms milliseconds.

the tcpdump as follow :

image

image

image

image

in tcpdump file, I found that :

  1. two [PSH] almost sent at same time
  2. the server only response one [ACK] with 2nd [PSH]'s seq.
  3. the 1st [PSH] receive no [ACK]

I thought it was server problem.

is this modbus robust to resend the request?

Just help to first use

Hi,
I'm using a master simulator, I have created some registries and I'm trying to read the value using the example documented in the home page of this project.

I'm trying to read a registry to the index 2 using the unitid 1.
Here the code:



 CompletableFuture<ReadHoldingRegistersResponse> future =
            master.sendRequest(new ReadHoldingRegistersRequest(2, 3), 1);

        future.whenCompleteAsync((response, ex) -> {
            if (response != null) {
            	//long myValue = response.getRegisters().order(ByteOrder.LITTLE_ENDIAN).readUnsignedInt();
            	//long myValue = response.getRegisters().readUnsignedInt();
            	int myValue = response.getRegisters().readInt();
            	System.out.println("Risultato int = " + myValue);
                ReferenceCountUtil.release(response);
            } else {
                logger.error("Completed exceptionally, message={}", ex.getMessage(), ex);
            }
            scheduler.schedule(() -> sendAndReceive(master), 1, TimeUnit.SECONDS);
        }, Modbus.sharedExecutor());

The result is

Risultato int = 0

but the correct value of the registry is "5".
Can anyone help me?

Thanks

Francesco

Could you please release 1.2.1 version?

1.2.0 was released on 2020-11-16, and later no versions are release.
Compare master with the release/1.2.0, some difference appeared.
Could you please release a new version maybe named 1.2.1 version?
Any answers are appreciated.

Error decoding ReadMultipleRegistersRequest

User reported this error:

Caused by: java.lang.IllegalArgumentException: maxCapacity: -128 (expected:>= 0)
        at io.netty.buffer.AbstractByteBuf.<init>(AbstractByteBuf.java:67)
        atio.netty.buffer.AbstractDerivedByteBuf.<init>(AbstractDerivedByteBuf.java:31)
        atio.netty.buffer.AbstractUnpooledSlicedByteBuf.<init>(AbstractUnpooledSlicedByteBuf.java:38)
        at io.netty.buffer.UnpooledSlicedByteBuf.<init>(UnpooledSlicedByteBuf.java:24)
        at io.netty.buffer.AbstractByteBuf.slice(AbstractByteBuf.java:1188)
        at io.netty.buffer.AbstractByteBuf.readSlice(AbstractByteBuf.java:836)
        at com.digitalpetri.modbus.codec.ModbusRequestDecoder.decodeWriteMultipleRegisters(ModbusRequestDecoder.java:136)
        at com.digitalpetri.modbus.codec.ModbusRequestDecoder.decodeResponse(ModbusRequestDecoder.java:71)
        at com.digitalpetri.modbus.codec.ModbusRequestDecoder.decode(ModbusRequestDecoder.java:44)
        at com.digitalpetri.modbus.codec.ModbusTcpCodec.decode(ModbusTcpCodec.java:75)

This is caused by ModbusRequestDecoder erroneously reading a signed instead of unsigned byte here:

Release version 1.2.0

Hello,

Are you planning soon to release the version "1.2.0.RELEASE" ?

The latest version i could find is 1.1.1.

Thank you for this project,
Ashi

Atomic operation for single coil requests

I am looking for a modbus library to integrate within an JavaEE application server.

Basically I need a stateless option to for a single coil request:

        ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder(endpoint)
            .setPort(PORT)
            .build();
        ModbusTcpMaster master = new ModbusTcpMaster(config);
        WriteSingleCoilRequest req = new WriteSingleCoilRequest(channel, enabled);
        master.sendRequest(req, 0).thenAccept(response ->
        {
            ReferenceCountUtil.release(response);
        });

This method can be called multiple times and even in parallel. I noticed that after this the library still have some open threads. Calling Modbus.releaseSharedResources(); does not work for parallel or fast consecutive calls.

I think it would be good if in a method like disconnect all resources are released and provide a thread safe operation.

Performance problem in 1.2.0

I have a little problem with the library taking unexplainable pauses from time to time. I have a heavy polling complex application which needs to have reliable poll cycles of 20 ms for each of several devices. The library is working well even with with lower cycles however from time to time there is a noticeable delay for 200-600 ms for all threads using the library. It looks like there is a resource leak going on for this short period and then it is proceeding without problems.
I have traced all outer possibilities without anything strange like JVM pauses, GC pauses, CPU, System I/O, Networking (ping under 1 ms), Slaves itself and so on however I can not exclude anything yet.

I am using the library like this:

	public static int sendRead(final ModbusTcpMaster master, ReadDiscreteInputsRequest input, Benchmarker benchmarker) throws Exception {
		if (benchmarker != null) benchmarker.split("REQUEST");
		final CompletableFuture<ReadDiscreteInputsResponse> future = master.sendRequest(input, 0);
		ReadDiscreteInputsResponse response = null;
		if (benchmarker != null) benchmarker.split("RESPONSE");
		try {
			response = future.get();
			return response.getInputStatus().readUnsignedByte();
		} finally {
			if (response != null) {
				ReferenceCountUtil.release(response);
			}
		}
        }

Benchmarker is a utility class for tracing the times. The delay is happening in the response section where it is waiting for the result. This method is called up to thousand times per second and it is working but sometimes it starves.
I know it is very hard to say without hands on such a complex system, so my question is rather related to resources sensitive bottlenecks to look for maybe in the underlying Netty world? How can such a problem be traced, are there any tips?

Consider upgrading netty to 4.1.x ?

Hello kevinherron!

Other components of my project depend on netty 4.1, but this repository depends on netty 4.0, netty conflicts.
Consider upgrading netty to 4.1.x ?

ClosedChannelException

An 'ClosedChannelException' occurred while writing, but the 'stateContext' has not changed.

ModbusTcpMaster.java:

         ch.writeAndFlush(new ModbusTcpPayload(txId, (short) unitId, request)).addListener(f -> {
                if (!f.isSuccess()) {
                    // How to fix? Whether we can?
                    /*Throwable cause = f.cause();
                    if (f.cause() instanceof ClosedChannelException) {
                        stateContext.handleEvent(ConnectionEvent.ChannelClosed);
                        cause = new RuntimeException("Channel closed!", f.cause());
                    }*/
                    PendingRequest<?> p = pendingRequests.remove(txId);
                    if (p != null) {
                        p.promise.completeExceptionally(f.cause());
                        p.timeout.cancel();
                    }
                }
            });

How to read data in batches

I just started using this project, and I'm very confused about how to read data in batches. If you can, please guide me to complete this code.

Could I use one common ModbusTcpMaster for multi-thread sending diffrent requests ? Would these threads be blocked ?

My step is like this.

  1. create a common ModbusTcpMaster instance.
public CompletableFuture<ModbusTcpMaster> createModbusConnector(String ipAddr, int port) {
        if (modbusMaster == null) {
            ModbusTcpMasterConfig masterConfig = new ModbusTcpMasterConfig.Builder(ipAddr).setPort(port).setTimeout(Duration.parse(TIMEOUT_DURATION)).build();
            modbusMaster = new ModbusTcpMaster(masterConfig);
        }
        return modbusMaster.connect();
    }
  1. then invoke collectModbusData for multi-thread
    public CompletableFuture<Boolean> collectModbusData(ModbusNetworkAddress address, ModbusParamWrapper paramWrapper) throws ExecutionException, InterruptedException, TimeoutException {
        List<CompletableFuture<Boolean>> futureList = new ArrayList<>();
        ModbusMasterUtil modbusMasterUtil = new ModbusMasterUtil();
        modbusMasterUtil.createModbusConnector(address.getIpAddr(), address.getPort());
        futureList.add(collectModbusData(modbusMasterUtil, paramWrapper.getCoilParamSet(), ModbusParam.CODE_READ_COIL));
        futureList.add(collectModbusData(modbusMasterUtil, paramWrapper.getDiscreteInputParamSet(), ModbusParam.CODE_READ_DISCRETE_INPUT));
        futureList.add(collectModbusData(modbusMasterUtil, paramWrapper.getHoldingRegisterParamSet(), ModbusParam.CODE_READ_HOLDING_REGISTER));
        futureList.add(collectModbusData(modbusMasterUtil, paramWrapper.getInputRegisterParamSet(), ModbusParam.CODE_READ_INPUT_REGISTER));
        CompletableFuture<Boolean> future = matchFutureList(futureList);
//        future.whenCompleteAsync((result, throwable) -> {
//            modbusMasterUtil.disposeModbusConnector();
//            if (throwable != null) {
//                future.completeExceptionally(throwable);
//            }
//        });
        return future;
    }
  1. collectModbusData function will create a supplyAsync process use customized thread pool "modbusExecutor".
   public CompletableFuture<Boolean> collectModbusData(ModbusMasterUtil modbusMasterUtil, ModbusParam modbusParam, int code) {
        CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
            CompletableFuture<int[]> registerFuture = null;
            switch (code) {
                case ModbusParam.CODE_READ_COIL:
                    registerFuture = modbusMasterUtil.readCoils(modbusParam.getSlaveId(), modbusParam.getAddress(), modbusParam.getQuantity());
                    break;
                case ModbusParam.CODE_READ_DISCRETE_INPUT:
                    registerFuture = modbusMasterUtil.readDiscreteInputs(modbusParam.getSlaveId(), modbusParam.getAddress(), modbusParam.getQuantity());
                    break;
                case ModbusParam.CODE_READ_HOLDING_REGISTER:
                    registerFuture = modbusMasterUtil.readHoldingRegisters(modbusParam.getSlaveId(), modbusParam.getAddress(), modbusParam.getQuantity());
                    break;
                case ModbusParam.CODE_READ_INPUT_REGISTER:
                    registerFuture = modbusMasterUtil.readInputRegisters(modbusParam.getSlaveId(), modbusParam.getAddress(), modbusParam.getQuantity());
                    break;
                default:
                    break;
            }
            if (registerFuture != null) {
                try {
                    int[] registerValues = registerFuture.get();
                    if (registerValues != null && registerValues.length > 0) {
                        modbusParam.setRegisterValues(registerValues);
                        return true;
                    } else {
                        return false;
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } catch (ExecutionException e) {
                    throw new RuntimeException(e);
                }
            } else {
                return false;
            }
        }, modbusExecutor);
        return future;
    }
  1. finally, they will invoke into ModbusMasterUtil class and sendRequest.
    public CompletableFuture<int[]> readCoils(int slaveId, int address, int quantity) {
        CompletableFuture<ReadCoilsResponse> futureResponse = modbusMaster.sendRequest(new ReadCoilsRequest(address, quantity),
                slaveId);
        return futureResponse.thenApply(response -> {
            ByteBuf byteBuf = response.getCoilStatus();
            int[] values = new int[quantity];
            int minimum = Math.min(quantity, byteBuf.capacity() * 8);
            for (int i = 0; i < minimum; i += 8) {
                setBooleanArray(byteBuf.readUnsignedByte(), values, i, Math.min(minimum - i, 8));
            }
            ReferenceCountUtil.release(response);
            return values;
        });
    }
    public CompletableFuture<int[]> readDiscreteInputs(int slaveId, int address, int quantity) {
        CompletableFuture<ReadDiscreteInputsResponse> futureResponse = modbusMaster.sendRequest(new ReadDiscreteInputsRequest(address, quantity),
                slaveId);
        return futureResponse.thenApply(response -> {
            ByteBuf byteBuf = response.getInputStatus();
            int[] values = new int[quantity];
            int minimum = Math.min(quantity, byteBuf.capacity() * 8);
            for (int i = 0; i < minimum; i += 8) {
                setBooleanArray(byteBuf.readUnsignedByte(), values, i, Math.min(minimum - i, 8));
            }
            ReferenceCountUtil.release(response);
            return values;
        });
    }
    public CompletableFuture<int[]> readHoldingRegisters(int slaveId, int address, int quantity) {
        CompletableFuture<ReadHoldingRegistersResponse> futureResponse = modbusMaster.sendRequest(new ReadHoldingRegistersRequest(address, quantity),
                slaveId);
        return futureResponse.thenApply(response -> {
            ByteBuf byteBuf = response.getRegisters();
            int[] values = new int[quantity];
            for (int i = 0; i < byteBuf.capacity() / 2; i++) {
                values[i] = byteBuf.readUnsignedShort();
            }
            ReferenceCountUtil.release(response);
            return values;
        });
    }
    public CompletableFuture<int[]> readInputRegisters(int slaveId, int address, int quantity) {
        CompletableFuture<ReadInputRegistersResponse> futureResponse = modbusMaster.sendRequest(new ReadInputRegistersRequest(address, quantity),
                slaveId);
        return futureResponse.thenApply(response -> {
            ByteBuf byteBuf = response.getRegisters();
            int[] values = new int[quantity];
            for (int i = 0; i < byteBuf.capacity() / 2; i++) {
                values[i] = byteBuf.readUnsignedShort();
            }
            ReferenceCountUtil.release(response);
            return values;
        });
    }

Modbus Master as TCP server

Sorry, I don't know about the modbus specification.

I want to ask if I can make the modbus master as a TCP server and the slave as a TCP client.
Can I make the slave on the local network access the server on the Internet?

WriteMultipleCoilsRequest failure

When using a WriteMultipleCoilsRequest, if the quantity parameter is not a multiple of 8, the request fails to send, and a response timeout ensues.
The issue appears to be with the formula used to calculate the number of bytes that are needed to hold the quantity of bits to be written. Currently the formula (in ModbusRequestEncoder.encodeWriteMultipleCoils() ) is:

        int byteCount = (request.getQuantity() / 8) + (request.getQuantity() % 8);

This should be:

        int byteCount = 1 + (request.getQuantity() -1) / 8;

The ModbusRequestSerializationTest could be enhanced to check for these as below:

    @DataProvider
    private Object[][] getAddressAndNumCoilsAndCoilValues() {
        return new Object[][]{
                {0, 1, new byte[]{0x01}},
                {0, 2, new byte[]{0x02}},
                {0, 3, new byte[]{0x04}},
                {0, 4, new byte[]{0x08}},
                {0, 5, new byte[]{0x10}},
                {0, 6, new byte[]{0x20}},
                {0, 7, new byte[]{0x40}},
                {0, 8, new byte[]{(byte)0x80}},
                {0, 9, new byte[]{0x01, 0x01}},
                {0, 10, new byte[]{0x01, 0x02}},
                {0, 11, new byte[]{0x01, 0x04}},
                {0, 12, new byte[]{0x01, 0x08}},
                {0, 13, new byte[]{0x01, 0x10}},
                {0, 14, new byte[]{0x01, 0x20}},
                {0, 15, new byte[]{0x01, 0x40}},
                {0, 16, new byte[]{0x01, (byte)0x80}},
                {0, 17, new byte[]{0x02, 0x01, 0x01}}
        };
    }
.
.
.
    @Test(dataProvider = "getAddressAndNumCoilsAndCoilValues")
    public void testWriteMultipleCoilsRequest(int address, int numCoils, byte[] values) {
        WriteMultipleCoilsRequest request = new WriteMultipleCoilsRequest(address, numCoils, values);
        request.retain().content().markReaderIndex();

        ByteBuf encoded = encoder.encode(request, Unpooled.buffer());
        WriteMultipleCoilsRequest decoded = (WriteMultipleCoilsRequest) decoder.decode(encoded);

        request.content().resetReaderIndex();

        assertEquals(request.getAddress(), decoded.getAddress());
        assertEquals(request.getQuantity(), decoded.getQuantity());
        assertEquals(request.getValues(), decoded.getValues());
    }

The problem is detected as a IndexOutOfBoundsException, which does not get reported to the Modbus sendRequest() future.

Getting issues with below lines

ModbusRequestDecoder.java (line 127, 136)
ByteBuf values = buffer.readSlice(byteCount).retain();

ModbusResponseDecoder.java (line 110, 117, 124)
ByteBuf registers = buffer.readSlice(byteCount).retain();

Allow connection error logging to be overridden

I'm getting quite some error messages in my log like the one below. unfortunately, there seem to be no way of controlling what gets logged and how (unless I'm overlooking something), since this is hard-coded into ModbusTcpMaster::onExceptionCaught, which is a private function. While I understand that the handling of the error mush happen here (e.g., to call failPendingRequests and ctx.close), it would be nice to have an extension point for how this is treated as far as logging is concerned. I would prefer to NOT log this particular issue (i.e., the "other end" closing the connection) as an Error (perhaps I'd log it as a warning, or not at all, since it's rather benign and almost "normal").

Perhaps a protected method could be added, called from onExceptionCaught, where the default implementation is what you do now:

       logger.error("Exception caught: {}", cause.getMessage(), cause);

but allowing me to handle this in some other way for select exceptions (such as this "Connection reset by peer" case). Or perhaps there's some better way to get control over this behavior, avoiding polluting my log file with scary-lookin ERRORs for such rather benign occurences.

-JM

ERROR [2017-06-21 09:10:03,026] com.digitalpetri.modbus.master.ModbusTcpMaster: Exception caught: Connection reset by peer
! java.io.IOException: Connection reset by peer
! at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
! at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
! at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
! at sun.nio.ch.IOUtil.read(IOUtil.java:192)
! at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
! at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:288)
! at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1100)
! at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:366)
! at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:118)
! at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:642)
! at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:565)
! at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:479)
! at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:441)
! at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
! at java.lang.Thread.run(Thread.java:745)

Slave example exits immediately since resource management changed

In commit 3066f96 resource management changed, especially the event scheduler was changed to use a thread factory which creates daemon threads.

This changes the behavior of the library slightly: before the commit, the executor prevented the program from terminating, e.g. after exiting main. After the commit, all modbus threads are daemon threads, so exiting main (more correct: all non-daemon threads) will terminate the program.

You can see this in the slave example, whose only task is to answer the requests of the master (in the background), thus exiting immediately.

I don't know what the best strategy for programs working exactly like the slave example (just responding to requests) is. Except, of course, preventing main to exit by and endless sleep loop, but doesn't feel like "the best" ;)

Threading problems

We are polling a modbus system with very high frequency. We are facing problems that there are major delays when new threads are spawned for every read request and the system is very busy with other threads. Is there a way to have the calls running in a specific thread without spawning? We are aware this might conflict with the whole design.

ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder(ioParameter.getAddress())
                        .setPort(ioParameter.getPort()).setTimeout(Duration.ofSeconds(2))
                        .build();
                modbusClient = new ModbusTcpMaster(config);
                modbusClient.connect();

      CompletableFuture future = modbusClient.sendRequest(new ReadDiscreteInputsRequest(0, 8), 0);
      ^^^^^ Thread is spawned and execution is not guaranteed ^^^^^

Version: 1.1.1

error

`package com.modbus.tcp.util;

import com.digitalpetri.modbus.FunctionCode;
import com.digitalpetri.modbus.codec.Modbus;
import com.digitalpetri.modbus.master.ModbusTcpMaster;
import com.digitalpetri.modbus.master.ModbusTcpMasterConfig;
import com.digitalpetri.modbus.requests.;
import com.digitalpetri.modbus.responses.
;
import io.netty.buffer.ByteBuf;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**

  • @Version: V1.0

  • @description: modbus TCP协议 数据读取写入

  • @Date: 2021-02-04
    */
    @slf4j
    public class ModbusMasterTCPUtils {

    /**

    • tcp连接对象
      /
      private static ModbusTcpMaster modbusTcpMaster;
      /
      *
    • modubs从站ID
      /
      private static final Integer UNIT_ID = 1;
      /
      *
    • 成功代码
      /
      private static final String SUCCESS_CODE = "0x000000";
      /
      *
    • 与modubs连接异常
      */
      private static final String COON_FAIL_CODE = "0x000001";

    /**

    • @description: 初始化连接
    • @param:
    • @return: 结果值
      */
      public static String init(String IP, Integer PORT) {
      try {
      if (modbusTcpMaster == null) {
      // 创建配置
      ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder(IP).setPort(PORT).build();
      // 新建连接
      modbusTcpMaster = new ModbusTcpMaster(config);
      }
      return SUCCESS_CODE;
      } catch (Exception e) {
      log.error("ModbusMasterTCP::init - " + e.getMessage() + "(0x000001)" +
      "\r\n" + Arrays.toString(e.getStackTrace()));
      return COON_FAIL_CODE;
      }
      }

    /**

    • @description: 释放连接
    • @param:
    • @return: 结果值
      */
      private static String release() {
      try {
      if (modbusTcpMaster != null) {
      modbusTcpMaster.disconnect();
      }
      Modbus.releaseSharedResources();
      return SUCCESS_CODE;
      } catch (Exception e) {
      return COON_FAIL_CODE;
      }
      }

    /**

    • 读取InputRegisters模拟量数据

    • @param address 寄存器开始地址

    • @param quantity 数量

    • @param unitId ID

    • @return 读取值

    • @throws InterruptedException 异常

    • @throws ExecutionException 异常
      */
      public static Number readInputRegisters(int address, int quantity, int unitId)
      throws InterruptedException, ExecutionException {
      Number result = null;
      CompletableFuture future = modbusTcpMaster
      .sendRequest(new ReadInputRegistersRequest(address, quantity), unitId);
      // 工具类做的同步返回.实际使用推荐结合业务进行异步处理
      ReadInputRegistersResponse readInputRegistersResponse = future.get();

      if (readInputRegistersResponse != null) {
      ByteBuf buf = readInputRegistersResponse.getRegisters();
      result = buf.readFloat();
      ReferenceCountUtil.release(readInputRegistersResponse);
      }
      return result;
      }

    /**

    • @description: readDemo
    • @param:
    • @return:
      */
      public static void readDemo(String ip, Integer port) {
      try {
      // 初始化资源
      init(ip, port);
      System.out.println("readDemo=" + readInputRegisters(1, 2, 1));
      System.out.println("readDemo=" + readInputRegisters(3, 2, 1));
      System.out.println("readDemo=" + readInputRegisters(5, 2, 1));
      System.out.println("readDemo=" + readInputRegisters(7, 2, 1));
      System.out.println("readDemo=" + readInputRegisters(9, 2, 1));
      release();
      } catch (Exception e) {
      e.printStackTrace();
      }
      }

    /**

    • @description: main
    • @param:
    • @return:
      */
      public static void main(String[] args) {
      readDemo("172.16.2.253 ",502);
      // writeDemo3();
      // release();
      }

}
`

error:

java.util.concurrent.ExecutionException: java.net.UnknownHostException: 172.16.2.253 : nodename nor servname provided, or not known at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395) at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1999) at com.modbus.tcp.util.ModbusMasterTCPUtils.readInputRegisters(ModbusMasterTCPUtils.java:105) at com.modbus.tcp.util.ModbusMasterTCPUtils.readDemo(ModbusMasterTCPUtils.java:124) at com.modbus.tcp.util.ModbusMasterTCPUtils.main(ModbusMasterTCPUtils.java:144) Caused by: java.net.UnknownHostException: 172.16.2.253 : nodename nor servname provided, or not known at java.base/java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method) at java.base/java.net.InetAddress$PlatformNameService.lookupAllHostAddr(InetAddress.java:929) at java.base/java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1515) at java.base/java.net.InetAddress$NameServiceAddresses.get(InetAddress.java:848) at java.base/java.net.InetAddress.getAllByName0(InetAddress.java:1505) at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1364) at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1298) at java.base/java.net.InetAddress.getByName(InetAddress.java:1248) at io.netty.util.internal.SocketUtils$8.run(SocketUtils.java:156) at io.netty.util.internal.SocketUtils$8.run(SocketUtils.java:153) at java.base/java.security.AccessController.doPrivileged(Native Method) at io.netty.util.internal.SocketUtils.addressByName(SocketUtils.java:153) at io.netty.resolver.DefaultNameResolver.doResolve(DefaultNameResolver.java:41) at io.netty.resolver.SimpleNameResolver.resolve(SimpleNameResolver.java:61) at io.netty.resolver.SimpleNameResolver.resolve(SimpleNameResolver.java:53) at io.netty.resolver.InetSocketAddressResolver.doResolve(InetSocketAddressResolver.java:55) at io.netty.resolver.InetSocketAddressResolver.doResolve(InetSocketAddressResolver.java:31) at io.netty.resolver.AbstractAddressResolver.resolve(AbstractAddressResolver.java:106) at io.netty.bootstrap.Bootstrap.doResolveAndConnect0(Bootstrap.java:206) at io.netty.bootstrap.Bootstrap.access$000(Bootstrap.java:46) at io.netty.bootstrap.Bootstrap$1.operationComplete(Bootstrap.java:180) at io.netty.bootstrap.Bootstrap$1.operationComplete(Bootstrap.java:166) at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:577) at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:551) at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:490) at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:615) at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:604) at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:104) at io.netty.channel.DefaultChannelPromise.trySuccess(DefaultChannelPromise.java:84) at io.netty.channel.AbstractChannel$AbstractUnsafe.safeSetSuccess(AbstractChannel.java:984) at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:504) at io.netty.channel.AbstractChannel$AbstractUnsafe.access$200(AbstractChannel.java:417) at io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:474) at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:834)

where could I store per connection variables?

where could I store per connection variables? I mean lets picture the situation: device connects to my slave server, write multiple registers and then read holding registers, I generate values in holding registers based on written registers values. So where exactly should I keep these values in-between of onWriteMultipleRegisters and onReadHoldingRegisters calls? I'm kinda out of options here or so it seems

Missing throws clause

I just updated to the latest version. When I tried to run the Tcp Master example, the compiler complained about an unhandled exception originating from the sharedEventLoop().shutdownGracefully().get(); call in the com.digitalpetri.modbus.codec.Modbus#releaseSharedResources. Indeed, java.util.concurrent.Future#get is declared as throwing InterruptedException, ExecutionException.

I fixed it by adding the same throws clause to releaseSharedResources(), like this.

    /** Shutdown/stop any shared resources that may be in use. */
    public static void releaseSharedResources() throws ExecutionException, InterruptedException {
        sharedExecutor().shutdown();
        sharedEventLoop().shutdownGracefully().get();
        sharedWheelTimer().stop();
    }

If you agree that's the correct fix, you may want to do likewise.

-JM

Custom FunctionCodes

Hallo

Is it possible to use modbus library with custom functions codes like 0x41 - 0x48 and 0x64 - 0x6E.
If not yet implemented would it be interesting to add this feature to library, so that custom manufacturer based functions can also be used with this library? If so I would like to support this great lib.

Best
Tim

Sending requests simultaneously

Hi,
Can I send multiple inquiries in parallel?
I have sth like that:

    private void test(){
    this.readHoldingRegisters(0x1,0x1)->thenCompose(response-> {
    if(response.getRegisters().getUnsignedShort(0) != 255)
                final CompletableFuture<ReadHoldingRegistersResponse> firstPart =
                        this.readHoldingRegisters(firstPartStartAddress - 0x9c40, firstPartEndAddress - firstPartStartAddress);
                final CompletableFuture<ReadHoldingRegistersResponse> secondPart =
                        this.readHoldingRegisters(secondPartStartAddress - 0x9c40, secondPartEndAddress - secondPartStartAddress);

                List<CompletableFuture<ReadHoldingRegistersResponse>> test  =Stream.of(firstPart,secondPart)
                        .collect(Collectors.toList());
                 //...create object etc 
    });
    }
    private CompletableFuture<ReadHoldingRegistersResponse> readHoldingRegisters(final int offset, final int length){
        return this.connection.sendRequest(new ReadHoldingRegistersRequest(offset, length), super.getSlaveId());
    }

Usually after ->thenCompose, only the first part will be called and from it I will get the answer, while from the second part I will not get the answer. If I comment the first part request then I'll get response from sencond part. But I can't get to the point where both answer in parallel. What's wrong?

How to configure the server slave id

I have followed the simple slave configuration and been working on improving it towards my project needs. However I have been unable to configure the slave ID, how can it be done? I am trying to achieve that the slave does not answer when the slave ID does not match the one I am requesting.

How to release all resources?

When I shutdown Tomcat server, it failed to close modbus related resources. Here is the error report:

11-Apr-2017 20:31:51.656 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [pool-41-thread-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
    java.lang.Thread.sleep(Native Method)
    io.netty.util.HashedWheelTimer$Worker.waitForNextTick(HashedWheelTimer.java:461)
    io.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:360)
    java.lang.Thread.run(Thread.java:745)
11-Apr-2017 20:31:51.657 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [nioEventLoopGroup-2-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
    sun.nio.ch.WindowsSelectorImpl$SubSelector.poll0(Native Method)
    sun.nio.ch.WindowsSelectorImpl$SubSelector.poll(WindowsSelectorImpl.java:296)
    sun.nio.ch.WindowsSelectorImpl$SubSelector.access$400(WindowsSelectorImpl.java:278)
    sun.nio.ch.WindowsSelectorImpl.doSelect(WindowsSelectorImpl.java:159)
    sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
    sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:622)
    io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:310)
    io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
    io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
    java.lang.Thread.run(Thread.java:745)
11-Apr-2017 20:31:51.657 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [threadDeathWatcher-3-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
    java.lang.Thread.sleep(Native Method)
    io.netty.util.ThreadDeathWatcher$Watcher.run(ThreadDeathWatcher.java:147)
    io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
    java.lang.Thread.run(Thread.java:745)
11-Apr-2017 20:31:51.658 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [ForkJoinPool-1-worker-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
    sun.misc.Unsafe.park(Native Method)
    java.util.concurrent.ForkJoinPool.awaitWork(ForkJoinPool.java:1824)
    java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1693)
    java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
11-Apr-2017 20:31:51.659 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [nioEventLoopGroup-2-2] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
    sun.nio.ch.WindowsSelectorImpl$SubSelector.poll0(Native Method)
    sun.nio.ch.WindowsSelectorImpl$SubSelector.poll(WindowsSelectorImpl.java:296)
    sun.nio.ch.WindowsSelectorImpl$SubSelector.access$400(WindowsSelectorImpl.java:278)
    sun.nio.ch.WindowsSelectorImpl.doSelect(WindowsSelectorImpl.java:159)
    sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
    sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:622)
    io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:310)
    io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
    io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
    java.lang.Thread.run(Thread.java:745)
11-Apr-2017 20:31:51.661 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@2bf57c77]) and a value of type [io.netty.util.internal.InternalThreadLocalMap] (value [io.netty.util.internal.InternalThreadLocalMap@5eeed32c]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
11-Apr-2017 20:31:51.662 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@2bf57c77]) and a value of type [io.netty.util.internal.InternalThreadLocalMap] (value [io.netty.util.internal.InternalThreadLocalMap@50fcdab9]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
11-Apr-2017 20:31:51.662 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@2bf57c77]) and a value of type [io.netty.util.internal.InternalThreadLocalMap] (value [io.netty.util.internal.InternalThreadLocalMap@148dc3df]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.

Could you take a look and tell me which methods should I call when shutting down my Tomcat server, thread pool#shutdown() or future#close() or something else? Thanks.

ERROR com.digitalpetri.modbus.examples.master.ReadCoilsMaster - Completed exceptionally, message=functionCode=ReadCoils, exceptionCode=IllegalFunction

ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder("localhost").build();
ModbusTcpMaster master = new ModbusTcpMaster(config);

    CompletableFuture<ReadCoilsResponse> future =
            master.sendRequest(new ReadCoilsRequest(0, 2), 0);

future.thenAccept(response -> {
ByteBuf coilStatus = response.getCoilStatus();

ReferenceCountUtil.release(response);

});

Report encoding/decoding errors to application layer

Right now if there's an exception thrown in the codec layer it gets caught and logged and then the channel is closed.

The problem: none of the request CompletableFutures get notified of this, and don't complete exceptionally until their timeout expires.

Usage sample to query a SUN2000 inverter?

Hi,

I'm totally new to modbus and I look for a way how I can query my SUN2000 using Java.

Can you provide a sample how I can use this project?

The interface definitions are here:
https://forum.iobroker.net/assets/uploads/files/1683548281975-sun2000ma-v100r001c20-modbus-interface-definitions.pdf

For example I want to get these values:

  • DC Power (32064)
  • Active Power (37113)
  • Charge and discharge power (37001)
  • Battery SOC (37004)

How would I do that?

And can I get them all at once or do I need to make separate queries?

Can I get multiple values in one block if I say "give me 37000 and the next 20 values"?

Kind regards,

Stefan

Modbus client

I've got a modbus server set up with ip and regular port=502.
I used a client.
Could you give me a hint as to how to implement read features of exposed modbus tables?

thanks a lot,
Charles

Unable to use

I tried the example code (master) against a Modicon PLC, on latest master "whenCompleteAsync" call of the "sendAndReceive" method is never completed. On wireshark I can see the TCP 3-way handshake completed successfully but no request at all.

I also tried version v1.1.1, on this one on wireshark TCP handshake ok, on this version I also can see request and response. But the "whenCompleteAsync" is never called.

Bootstrap customization callback should run last

Currently, the bootstrap customization callback runs before some channel options are set:

config.getBootstrapConsumer().accept(bootstrap);
bootstrap.group(config.getEventLoop())
.channel(NioSocketChannel.class)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) config.getTimeout().toMillis())
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new ModbusTcpCodec(new ModbusRequestEncoder(), new ModbusResponseDecoder()));
ch.pipeline().addLast(new ModbusTcpMasterHandler(master));
}
})

This means it's not possible for the allocator or connect timeout to be configured by the user.

The callback should be run after the default configuration options are set.

java.util.function.Consumer

Error:Gradle: ModbusTcpSlave.java:110-111: Lambda coming from jar file need their interfaces on the classpath to be compiled, unknown interfaces are java.util.function.Consumer

i got this error.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.