기은P
시간이 멈추는 장소
기은P
  • Programming (272)
    • 개발노트 (1)
    • FrontEnd (56)
      • ES&JS 문법 (14)
      • HTML&CSS (4)
      • React 기본 (18)
      • React 심화 (12)
      • React 이슈 (2)
      • Project 연습 (1)
      • Next.js (5)
    • Backend&Devops (33)
      • AWS (2)
      • Docker (9)
      • Jenkins (6)
      • Nginx (6)
      • Node.js (1)
      • ElasticSearch (5)
      • 프레임워크&아키텍처 (2)
      • 암호화 (0)
      • 기타 (2)
    • 알고리즘 (3)
    • C# (8)
      • WPF (8)
    • Java (51)
      • 순수 Java (18)
      • RDF&Jena (12)
      • RCP&GEF (9)
      • JMX (5)
      • JMapper (3)
      • 오류해결 (4)
    • Database (21)
      • RDBMS (9)
      • NoSQL (2)
      • TSDB (1)
      • GraphQL (1)
      • Hibernate (3)
      • 데이터베이스 이론 (4)
      • Redis (1)
    • 프로토콜 (11)
      • Netty (4)
      • gRPC (5)
      • 프로토콜 개념 (2)
    • Server (4)
      • Linux (4)
    • 2020 정보처리기사 필기 (43)
      • 목차 (1)
      • 기출문제 (1)
      • 1과목 - 소프트웨어 설계 (6)
      • 2과목 - 소프트웨어 개발 (7)
      • 3과목 - 데이터베이스 구축 (8)
      • 4과목 - 프로그래밍 언어 활용 (7)
      • 5과목 - 정보시스템 구축 관리 (10)
    • 2020 정보처리기사 실기 (31)
      • 목차 (4)
      • 기출예상문제 (19)
      • 실기요약 (8)
    • 빅데이터분석기사 필기 (4)
      • 목차 (0)
      • 필기 요약 (3)
    • 전기 공학 (1)
      • CIM (1)
    • 산업자동화시스템 (3)
      • SCADA (1)
      • OPC UA (2)
    • 디자인패턴 (1)
    • 휴지통 (0)

공지사항

  • 공지사항/포스팅 예정 항목

최근 댓글

최근 글

전체 방문자
오늘
어제

티스토리

hELLO · Designed By 정상우.
기은P

시간이 멈추는 장소

Java/순수 Java

[Java] Java Modbus 사용법(JLibModbus)

2021. 2. 16. 14:58
반응형

JLibModbus 사용법

 

 

1. 개요

 

공식 github:: https://github.com/kochedykov/jlibmodbus

 

GitHub - kochedykov/jlibmodbus: JLibModbus is an implementation of the Modbus protocol v1.1b in java language.

JLibModbus is an implementation of the Modbus protocol v1.1b in java language. - GitHub - kochedykov/jlibmodbus: JLibModbus is an implementation of the Modbus protocol v1.1b in java language.

github.com

 

Java에서 사용할 수 있는 모드 버스로 Master와 Slave의 모드버스를 구성할 수 있습니다.

Modbus는 RS-232(시리얼) 또는 TCP의 프로토콜 형태로 구현할 수 있는데, 위 라이브러리는 TCP 프로토콜을 사용하는 라이브러리입니다.

위 라이브러리에서 지원하는 Modbus Function은 아래와 같습니다.

 

           * 0x01 - Read Coils

           * 0x02 - Read Discrete Inputs

           * 0x03 - Read Holding Registers

           * 0x04 - Read Input Registers

           * 0x05 - Write Single Coil

           * 0x06 - Write Single Register

           * 0x07 - Read Exception Status(serial line only)

           * 0x08 - Diagnostics(serial line only)

           * 0x0B - Get Comm Event Counter(serial line only)

           * 0x0C - Get Comm Event Log(serial line only)

           * 0x0F - Write Multiple Coils

           * 0x10 - Write Multiple Registers

           * 0x11 - Report Slave Id(serial line only)

           * 0x14 - Read File Record

           * 0x15 - Write File Record

           * 0x16 - Mask Write Register

           * 0x17 - Read Write Multiple Registers

           * 0x18 - Read Fifo Queue

           * 0x2B - Encapsulated Interface Tansport(Read Device Identification interface, (0x2B / 0x0E))

 

 

 

 

2. MasterTCP 구성 코드

 

Master 측에서는 Slave(Server)에 접속할 수 있는 정보(IP, Port)들을 TcpParameter 객체에 정의해둡니다.

후에 ModbusMaster 객체를 팩토리를 통해 초기화합니다.

Slave의 Address는 slaveId이고, 접속할 가상의 Slave의 주소는 1로 설정해둡니다.

Offset은 조회할 주소의 시작 주소입니다. 총 10개의 주소가 생성되었다면 0번째의 주소부터 조회를 한다는 의미이고, 그 밑에 있는 quantity 변수는 0번째부터 순서대로 10번째의 주소를 조회한다는 의미입니다.

Register는 int[] 의 return 값을 가지고, coils은 boolean[]의 return 값을 가집니다.

 

public class SimpleMasterTCP {

    static public void main(String[] args) {
        try {
            TcpParameters tcpParameters = new TcpParameters();

            //tcp parameters have already set by default as in example
            tcpParameters.setHost(InetAddress.getLocalHost());
            tcpParameters.setKeepAlive(true);
            tcpParameters.setPort(Modbus.TCP_PORT);

            //if you would like to set connection parameters separately,
            // you should use another method: createModbusMasterTCP(String host, int port, boolean keepAlive);
            ModbusMaster m = ModbusMasterFactory.createModbusMasterTCP(tcpParameters);
            Modbus.setAutoIncrementTransactionId(true);

            int slaveId = 1;
            int offset = 0;
            int quantity = 10;

            try {
                // since 1.2.8
                if (!m.isConnected()) {
                    m.connect();
                }

                // at next string we receive ten registers from a slave with id of 1 at offset of 0.
                int[] registerValues = m.readHoldingRegisters(slaveId, offset, quantity);

                for (int value : registerValues) {
                    System.out.println("Address: " + offset++ + ", Value: " + value);
                }
                // also since 1.2.8.4 you can create your own request and process it with the master
                offset = 0;
                ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest();
                request.setServerAddress(1);
                request.setStartAddress(offset);
                request.setTransactionId(0);
                ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) m.processRequest(request);
                // you can get either int[] containing register values or byte[] containing raw bytes.
                for (int value : response.getRegisters()) {
                    System.out.println("Address: " + offset++ + ", Value: " + value);
                }
            } catch (ModbusProtocolException e) {
                e.printStackTrace();
            } catch (ModbusNumberException e) {
                e.printStackTrace();
            } catch (ModbusIOException e) {
                e.printStackTrace();
            } finally {
                try {
                    m.disconnect();
                } catch (ModbusIOException e) {
                    e.printStackTrace();
                }
            }
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

 

 

 

3. SlaveTCP 구성 코드

 

Slave 측에서는 Socket을 활용해 Master가 조회할 수 있는 Server(Ip, Port)를 열고, Master측에서 특정 이벤트(writeSingleCoil, ReadSingleHoldingRegister 등)을 요청할 때 Slave에서 처리할 이벤트의 내용을 정의하는 이벤트 핸들러를 생성하여 DataHolder에 등록해둡니다.

Slave는 가상의 Slave(테스트용 시뮬레이터)이므로 해당 모드버스의 Server Address(여기서는 1)를 정의하고, Coil과 Register의 주소와 값을 정의합니다.

아래 코드에서는 HoldingRegister 객체를 생성할 때의 인자를 10으로 두었는데, 이는 총 10개의 Register에서 10개의 주소를 생성해서 사용한다는 의미이고, hr.set(10, 12345)는 10번째 주소의 Register값을 12345로 정의한다는 의미입니다.

위와 같은 형태로 주소와 값을 임의로 정의하고 slave 객체에서 master의 연결과 응답을 기다리는 스레드를 구현한 형태로 되어있습니다.

public class SimpleSlaveTCP {

    static public void main(String[] argv) {

        try {

            final ModbusSlave slave;

            TcpParameters tcpParameters = new TcpParameters();

            tcpParameters.setHost(InetAddress.getLocalHost());
            tcpParameters.setKeepAlive(true);
            tcpParameters.setPort(Modbus.TCP_PORT);

            slave = ModbusSlaveFactory.createModbusSlaveTCP(tcpParameters);
            Modbus.setLogLevel(Modbus.LogLevel.LEVEL_DEBUG);

            MyOwnDataHolder dh = new MyOwnDataHolder();
            dh.addEventListener(new ModbusEventListener() {
                @Override
                public void onWriteToSingleCoil(int address, boolean value) {
                    System.out.print("onWriteToSingleCoil: address " + address + ", value " + value);
                }

                @Override
                public void onWriteToMultipleCoils(int address, int quantity, boolean[] values) {
                    System.out.print("onWriteToMultipleCoils: address " + address + ", quantity " + quantity);
                }

                @Override
                public void onWriteToSingleHoldingRegister(int address, int value) {
                    System.out.print("onWriteToSingleHoldingRegister: address " + address + ", value " + value);
                }

                @Override
                public void onWriteToMultipleHoldingRegisters(int address, int quantity, int[] values) {
                    System.out.print("onWriteToMultipleHoldingRegisters: address " + address + ", quantity " + quantity);
                }
            });

            slave.setDataHolder(dh);
            ModbusHoldingRegisters hr = new ModbusHoldingRegisters(10);
            hr.set(0, 12345);
            slave.getDataHolder().setHoldingRegisters(hr);
            slave.setServerAddress(1);
            /*
             * using master-branch it should be #slave.open();
             */
            slave.listen();

            /*
             * since 1.2.8
             */
            if (slave.isListening()) {
                Runtime.getRuntime().addShutdownHook(new Thread() {
                    @Override
                    public void run() {
                        synchronized (slave) {
                            slave.notifyAll();
                        }
                    }
                });

                synchronized (slave) {
                    slave.wait();
                }

                /*
                 * using master-branch it should be #slave.close();
                 */
                slave.shutdown();
            }
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public interface ModbusEventListener {
        void onWriteToSingleCoil(int address, boolean value);

        void onWriteToMultipleCoils(int address, int quantity, boolean[] values);

        void onWriteToSingleHoldingRegister(int address, int value);

        void onWriteToMultipleHoldingRegisters(int address, int quantity, int[] values);
    }

    public static class MyOwnDataHolder extends DataHolder {

        final List<ModbusEventListener> modbusEventListenerList = new ArrayList<ModbusEventListener>();

        public MyOwnDataHolder() {
            // you can place the initialization code here
            /*
            something like that:
            setHoldingRegisters(new SimpleHoldingRegisters(10));
            setCoils(new Coils(128));
            ...
            etc.
             */
        }

        public void addEventListener(ModbusEventListener listener) {
            modbusEventListenerList.add(listener);
        }

        public boolean removeEventListener(ModbusEventListener listener) {
            return modbusEventListenerList.remove(listener);
        }

        @Override
        public void writeHoldingRegister(int offset, int value) throws IllegalDataAddressException, IllegalDataValueException {
            for (ModbusEventListener l : modbusEventListenerList) {
                l.onWriteToSingleHoldingRegister(offset, value);
            }
            super.writeHoldingRegister(offset, value);
        }

        @Override
        public void writeHoldingRegisterRange(int offset, int[] range) throws IllegalDataAddressException, IllegalDataValueException {
            for (ModbusEventListener l : modbusEventListenerList) {
                l.onWriteToMultipleHoldingRegisters(offset, range.length, range);
            }
            super.writeHoldingRegisterRange(offset, range);
        }

        @Override
        public void writeCoil(int offset, boolean value) throws IllegalDataAddressException, IllegalDataValueException {
            for (ModbusEventListener l : modbusEventListenerList) {
                l.onWriteToSingleCoil(offset, value);
            }
            super.writeCoil(offset, value);
        }

        @Override
        public void writeCoilRange(int offset, boolean[] range) throws IllegalDataAddressException, IllegalDataValueException {
            for (ModbusEventListener l : modbusEventListenerList) {
                l.onWriteToMultipleCoils(offset, range.length, range);
            }
            super.writeCoilRange(offset, range);
        }
    }
}

 

 

반응형
저작자표시 변경금지 (새창열림)

'Java > 순수 Java' 카테고리의 다른 글

[Java] Birt Project 사용방법  (0) 2021.11.04
[Java] Lombok Annotation 정리  (0) 2020.09.07
[Java] Lombok Setter Custom  (0) 2020.09.07
[Java] Lombok 설치 방법  (0) 2020.09.07
[Java] 자바 코드 실행시간 측정 방법  (1) 2020.05.27
    'Java/순수 Java' 카테고리의 다른 글
    • [Java] Birt Project 사용방법
    • [Java] Lombok Annotation 정리
    • [Java] Lombok Setter Custom
    • [Java] Lombok 설치 방법
    기은P
    기은P
    기은P의 블로그 일상과 개발 관련 포스팅 #React #Typescript #Next #Nest https://github.com/kimdongjang

    티스토리툴바