modbus protocol uses [android serial communication]

modbus protocol uses [android serial communication]

The purpose of this paper is to use modbus protocol for serial communication between android and host computer. Communicate with other devices through serial port to transfer data. It can be understood as the communication between computer and keyboard and mouse.
I have uploaded the modbus protocol
modbus download protocol

serial connection

The method of connecting the serial port on the android side is actually to set the parameters of the serial port and open the underlying serial port file. Friends of android development can also ask the driver to help write. Of course, Google also has an official framework. Here I use the third-party framework and refer to the article of the great God
Refer to the great God link
Debug Wizard
First, configure in gradle:

implementation 'tp.xmaihh:serialport:2.1'

All source code
import java.io.ByteArrayOutputStream;

public class ByteArrayWriter extends ByteArrayOutputStream {
    public ByteArrayWriter() {
        super();
    }

    public void writeInt8(byte b)
    {
        this.write(b);
    }

    public void writeInt8(int b)
    {
        this.write((byte)b);
    }

    public void writeInt16(int n) {
        byte[] bytes = ByteUtil.fromInt16(n);
        this.write(bytes, 0, bytes.length);
    }

    public void writeInt16Reversal(int n){
        byte[] bytes=ByteUtil.fromInt16Reversal(n);
        this.write(bytes,0,bytes.length);
    }

    public void writeInt32(int n) {
        byte[] bytes = ByteUtil.fromInt32(n);
        this.write(bytes, 0, bytes.length);
    }

    public void writeBytes(byte[] bs,int len){
        this.write(bs,0,len);
    }

}
public class ByteUtil {

    public static String toHexString(byte[] input, String separator) {
        if (input == null) return null;

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < input.length; i++) {
            if (separator != null && sb.length() > 0) {
                sb.append(separator);
            }
            String str = Integer.toHexString(input[i] & 0xff);
            if (str.length() == 1) str = "0" + str;
            sb.append(str);
        }
        return sb.toString();
    }

    public static String toHexString(byte[] input) {
        return toHexString(input, " ");
    }

    public static byte[] fromInt32(int input) {
        byte[] result = new byte[4];
        result[3] = (byte) (input >> 24 & 0xFF);
        result[2] = (byte) (input >> 16 & 0xFF);
        result[1] = (byte) (input >> 8 & 0xFF);
        result[0] = (byte) (input & 0xFF);
        return result;
    }

    public static byte[] fromInt32R(int input) {
        byte[] result = new byte[4];
        result[0] = (byte) ((input >> 24) & 0xFF);
        result[1] = (byte) ((input >> 16) & 0xFF);
        result[2] = (byte) ((input >> 8) & 0xFF);
        result[3] = (byte) (input & 0xFF);
        return result;
    }

    public static byte[] fromInt16(int input) {
        byte[] result = new byte[2];
        result[0] = (byte) (input >> 8 & 0xFF);
        result[1] = (byte) (input & 0xFF);
        return result;
    }

    public static int fromBytes(byte a, byte b) {
        return ((a & 0xFF) << 8) + (b & 0xFF);
    }

    public static byte[] fromInt16Reversal(int input) {
        byte[] result = new byte[2];
        result[1] = (byte) (input >> 8 & 0xFF);
        result[0] = (byte) (input & 0xFF);
        return result;
    }

    public static int byteArrayToInt16(byte[] bytes) {
        int value = 0;
        for (int i = 0; i < 2; i++) {
            int shift = (1 - i) * 8;
            value += (bytes[i] & 0xFF) << shift;
        }
        return value;
    }

    /**
     * byte[]Turn int
     *
     * @param bytes Array that needs to be converted to int
     * @return int value
     */
    public static int byteArrayToInt(byte[] bytes) {
        int value = 0;
        for (int i = 0; i < 4; i++) {
            int shift = (3 - i) * 8;
            value += (bytes[i] & 0xFF) << shift;
        }
        return value;
    }

}

public class CRC16 {
    private static final byte[] crc16_tab_h = { (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
            (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00,
            (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
            (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01,
            (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
            (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1,
            (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
            (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
            (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
            (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
            (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00,
            (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
            (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
            (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01,
            (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
            (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1,
            (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
            (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
            (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
            (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01,
            (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
            (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
            (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01,
            (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40 };

    private static final byte[] crc16_tab_l = { (byte) 0x00, (byte) 0xC0, (byte) 0xC1, (byte) 0x01,
            (byte) 0xC3, (byte) 0x03, (byte) 0x02, (byte) 0xC2, (byte) 0xC6, (byte) 0x06, (byte) 0x07,
            (byte) 0xC7, (byte) 0x05, (byte) 0xC5, (byte) 0xC4, (byte) 0x04, (byte) 0xCC, (byte) 0x0C,
            (byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF, (byte) 0xCE, (byte) 0x0E, (byte) 0x0A,
            (byte) 0xCA, (byte) 0xCB, (byte) 0x0B, (byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8,
            (byte) 0xD8, (byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B, (byte) 0xDB, (byte) 0xDA,
            (byte) 0x1A, (byte) 0x1E, (byte) 0xDE, (byte) 0xDF, (byte) 0x1F, (byte) 0xDD, (byte) 0x1D,
            (byte) 0x1C, (byte) 0xDC, (byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15, (byte) 0xD7,
            (byte) 0x17, (byte) 0x16, (byte) 0xD6, (byte) 0xD2, (byte) 0x12, (byte) 0x13, (byte) 0xD3,
            (byte) 0x11, (byte) 0xD1, (byte) 0xD0, (byte) 0x10, (byte) 0xF0, (byte) 0x30, (byte) 0x31,
            (byte) 0xF1, (byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32, (byte) 0x36, (byte) 0xF6,
            (byte) 0xF7, (byte) 0x37, (byte) 0xF5, (byte) 0x35, (byte) 0x34, (byte) 0xF4, (byte) 0x3C,
            (byte) 0xFC, (byte) 0xFD, (byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E, (byte) 0xFE,
            (byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB, (byte) 0x39, (byte) 0xF9, (byte) 0xF8,
            (byte) 0x38, (byte) 0x28, (byte) 0xE8, (byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B,
            (byte) 0x2A, (byte) 0xEA, (byte) 0xEE, (byte) 0x2E, (byte) 0x2F, (byte) 0xEF, (byte) 0x2D,
            (byte) 0xED, (byte) 0xEC, (byte) 0x2C, (byte) 0xE4, (byte) 0x24, (byte) 0x25, (byte) 0xE5,
            (byte) 0x27, (byte) 0xE7, (byte) 0xE6, (byte) 0x26, (byte) 0x22, (byte) 0xE2, (byte) 0xE3,
            (byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20, (byte) 0xE0, (byte) 0xA0, (byte) 0x60,
            (byte) 0x61, (byte) 0xA1, (byte) 0x63, (byte) 0xA3, (byte) 0xA2, (byte) 0x62, (byte) 0x66,
            (byte) 0xA6, (byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65, (byte) 0x64, (byte) 0xA4,
            (byte) 0x6C, (byte) 0xAC, (byte) 0xAD, (byte) 0x6D, (byte) 0xAF, (byte) 0x6F, (byte) 0x6E,
            (byte) 0xAE, (byte) 0xAA, (byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69, (byte) 0xA9,
            (byte) 0xA8, (byte) 0x68, (byte) 0x78, (byte) 0xB8, (byte) 0xB9, (byte) 0x79, (byte) 0xBB,
            (byte) 0x7B, (byte) 0x7A, (byte) 0xBA, (byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF,
            (byte) 0x7D, (byte) 0xBD, (byte) 0xBC, (byte) 0x7C, (byte) 0xB4, (byte) 0x74, (byte) 0x75,
            (byte) 0xB5, (byte) 0x77, (byte) 0xB7, (byte) 0xB6, (byte) 0x76, (byte) 0x72, (byte) 0xB2,
            (byte) 0xB3, (byte) 0x73, (byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0, (byte) 0x50,
            (byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93, (byte) 0x53, (byte) 0x52, (byte) 0x92,
            (byte) 0x96, (byte) 0x56, (byte) 0x57, (byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94,
            (byte) 0x54, (byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D, (byte) 0x5F, (byte) 0x9F,
            (byte) 0x9E, (byte) 0x5E, (byte) 0x5A, (byte) 0x9A, (byte) 0x9B, (byte) 0x5B, (byte) 0x99,
            (byte) 0x59, (byte) 0x58, (byte) 0x98, (byte) 0x88, (byte) 0x48, (byte) 0x49, (byte) 0x89,
            (byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A, (byte) 0x4E, (byte) 0x8E, (byte) 0x8F,
            (byte) 0x4F, (byte) 0x8D, (byte) 0x4D, (byte) 0x4C, (byte) 0x8C, (byte) 0x44, (byte) 0x84,
            (byte) 0x85, (byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46, (byte) 0x86, (byte) 0x82,
            (byte) 0x42, (byte) 0x43, (byte) 0x83, (byte) 0x41, (byte) 0x81, (byte) 0x80, (byte) 0x40 };

    /**
     * Calculate CRC16 verification
     *
     * @param data
     *            Array to calculate
     * @return CRC16 Check value
     */
    public static int compute(byte[] data) {
        return compute(data, 0, data.length);
    }

    /**
     * Calculate CRC16 verification
     *
     * @param data
     *            Array to calculate
     * @param offset
     *            Starting position
     * @param len
     *            length
     * @return CRC16 Check value
     */
    public static int compute(byte[] data, int offset, int len) {
        return compute(data, offset, len, 0xffff);
    }

    /**
     * Calculate CRC16 verification
     *
     * @param data
     *            Array to calculate
     * @param offset
     *            Starting position
     * @param len
     *            length
     * @param preval
     *            Previous check value
     * @return CRC16 Check value
     */
    public static int compute(byte[] data, int offset, int len, int preval) {
        int ucCRCHi = (preval & 0xff00) >> 8;
        int ucCRCLo = preval & 0x00ff;
        int iIndex;
        for (int i = 0; i < len; ++i) {
            iIndex = (ucCRCLo ^ data[offset + i]) & 0x00ff;
            ucCRCLo = ucCRCHi ^ crc16_tab_h[iIndex];
            ucCRCHi = crc16_tab_l[iIndex];
        }
        int result=((ucCRCHi & 0x00ff) << 8) | (ucCRCLo & 0x00ff) & 0xffff;
        return result;
    }
}
import android.text.TextUtils;

public class ModbusError extends Exception {
    private int code;

    public ModbusError(int code, String message) {
        super(!TextUtils.isEmpty(message) ? message : "Modbus Error: Exception code = " + code);
        this.code = code;
    }

    public ModbusError(int code) {
        this(code, null);
    }

    public ModbusError(ModbusErrorType type, String message) {
        super(type.name() + ": " + message);
    }

    public ModbusError(String message) {
        super(message);
    }

    public int getCode() {
        return this.code;
    }
}
/**
 * Common Modbus communication errors
 */
public enum ModbusErrorType {
    ModbusError,
    ModbusFunctionNotSupportedError,
    ModbusDuplicatedKeyError,
    ModbusMissingKeyError,
    ModbusInvalidBlockError,
    ModbusInvalidArgumentError,
    ModbusOverlapBlockError,
    ModbusOutOfBlockError,
    ModbusInvalidResponseError,
    ModbusInvalidRequestError,
    ModbusTimeoutError
}
/**
 * Function code (decimal display)
 */
public class ModbusFunction {

    //Read coil register
    public static final int READ_COILS = 1;

    //Read discrete input register
    public static final int READ_DISCRETE_INPUTS = 2;

    //Read hold register
    public static final int READ_HOLDING_REGISTERS = 3;

    //Read input register
    public static final int READ_INPUT_REGISTERS = 4;

    //Write single coil register
    public static final int WRITE_SINGLE_COIL = 5;

    //Write a single holding register
    public static final int WRITE_SINGLE_REGISTER = 6;

    //Write multiple coil registers
    public static final int WRITE_COILS = 15;

    //Write multiple holding registers
    public static final int WRITE_HOLDING_REGISTERS = 16;
}

import tp.xmaihh.serialport.SerialHelper;

public class ModbusRtuMaster {

    private SerialHelper serialHelper;

    //The first uses the serialport third-party library
    public ModbusRtuMaster(SerialHelper serialHelper) {
        this.serialHelper = serialHelper;
    }


    /**
     * Assemble Modbus RTU message frame
     * @param slave Slave station address number
     * @param function_code Function code
     * @param starting_address Read register start address / write register address / write register start address
     * @param quantity_of_x Number of read registers / number of write registers
     * @param output_value The value that needs to be written to a single register
     * @param output_values An array that needs to be written to multiple registers
     * @return Convert the whole message frame to byte []
     * @throws ModbusError Modbus error
     */
    synchronized private byte[] execute(int slave, int function_code, int starting_address, int quantity_of_x,
                                        int output_value, int[] output_values) throws ModbusError {
        //Check whether the parameters comply with the provisions of the agreement
        if (slave < 0 || slave > 0xff) {
            throw new ModbusError(ModbusErrorType.ModbusInvalidArgumentError, "Invalid slave " + slave);
        }
        if (starting_address < 0 || starting_address > 0xffff) {
            throw new ModbusError(ModbusErrorType.ModbusInvalidArgumentError, "Invalid starting_address " + starting_address);
        }
        if (quantity_of_x < 1 || quantity_of_x > 0xff) {
            throw new ModbusError(ModbusErrorType.ModbusInvalidArgumentError, "Invalid quantity_of_x " + quantity_of_x);
        }

        // Construct request
        ByteArrayWriter request = new ByteArrayWriter();
        //Write slave address number
        request.writeInt8(slave);
        //Assemble the data area according to the function code
        //If it is a read register instruction
        if (function_code == ModbusFunction.READ_COILS || function_code == ModbusFunction.READ_DISCRETE_INPUTS
                || function_code == ModbusFunction.READ_INPUT_REGISTERS || function_code == ModbusFunction.READ_HOLDING_REGISTERS) {
            request.writeInt8(function_code);
            request.writeInt16(starting_address);
            request.writeInt16(quantity_of_x);

        } else if (function_code == ModbusFunction.WRITE_SINGLE_COIL || function_code == ModbusFunction.WRITE_SINGLE_REGISTER) {//Write single register instruction
            if (function_code == ModbusFunction.WRITE_SINGLE_COIL)
                if (output_value != 0) output_value = 0xff00;//If it is a coil register (FF 00 when writing 1, 00 00 when writing 0)
            request.writeInt8(function_code);
            request.writeInt16(starting_address);
            request.writeInt16(output_value);

        } else if (function_code == ModbusFunction.WRITE_COILS) {//Write multiple coil registers
            request.writeInt8(function_code);
            request.writeInt16(starting_address);
            request.writeInt16(quantity_of_x);

            //Calculate the number of bytes written
            int writeByteCount = (quantity_of_x / 8) + 1;///Satisfaction relationship - > (w / 8) + 1
            //If the number of bytes written = = 8, the number of bytes written is 1
            if (quantity_of_x % 8 == 0) {
                writeByteCount -= 1;
            }
            request.writeInt8(writeByteCount);

            int index = 0;
            //If the number of data written is > 8, it needs to be split
            int start = 0;//Array start position
            int end = 7;//Array end position
            int[] splitData = new int[8];
            //Write the split array circularly until the data with the number of elements < = 8 in the last group is left
            while (writeByteCount > 1) {
                writeByteCount--;
                int sIndex = 0;
                for (index = start; index <= end; index++){
                    splitData [sIndex++] = output_values[index];
                }
                //Data inversion whether you want to reverse depends on the data you send. If the high and low order is correct, you don't need to reverse
                splitData = reverseArr(splitData);
                //Write split array
                request.writeInt8(toDecimal(splitData));
                start = index;
                end += 8;
            }
            //Write the last remaining data
            int last = quantity_of_x - index;
            int[] tData = new int[last];
            System.arraycopy(output_values, index, tData, 0, last);
            //Data inversion whether you want to reverse depends on the data you send. If the high and low order is correct, you don't need to reverse
            tData = reverseArr(tData);
            request.writeInt8(toDecimal(tData));
        } else if (function_code == ModbusFunction.WRITE_HOLDING_REGISTERS) {//Write multiple holding registers
            request.writeInt8(function_code);
            request.writeInt16(starting_address);
            request.writeInt16(quantity_of_x);
            request.writeInt8(2 * quantity_of_x);
            //Write data
            for (int v : output_values) {
                request.writeInt16(v);
            }
        } else {
            throw new ModbusError(ModbusErrorType.ModbusFunctionNotSupportedError, "Not support function " + function_code);
        }
        byte[] bytes = request.toByteArray();
        //Calculate CRC check code
        int crc = CRC16.compute(bytes);
        request.writeInt16Reversal(crc);
        bytes = request.toByteArray();
        return bytes;
    }

    /**
     * Read multiple coil registers
     * @param slave Slave address
     * @param startAddress Starting address
     * @param numberOfPoints Read the number of coil registers
     * @throws ModbusError Modbus error
     */
    public void readCoils(int slave, int startAddress, int numberOfPoints) throws ModbusError {
        byte[] sendBytes = execute(slave, ModbusFunction.READ_COILS, startAddress, numberOfPoints, 0, null);
        this.serialHelper.send(sendBytes);
    }
    //Read single coil register
    public void readCoil(int slave, int address) throws ModbusError {
        readCoils(slave, address, 1);
    }

    /**
     * Read multiple holding registers
     * @param slave Slave address
     * @param startAddress Starting address
     * @param numberOfPoints Number of read holding registers
     * @throws ModbusError Modbus error
     */
    public void readHoldingRegisters(int slave, int startAddress, int numberOfPoints) throws ModbusError {
        byte[] sendBytes = execute(slave, ModbusFunction.READ_HOLDING_REGISTERS, startAddress, numberOfPoints, 0, null);
        this.serialHelper.send(sendBytes);
    }

    //Read single holding register
    public void readHoldingRegister(int slave, int address) throws ModbusError {
        readHoldingRegisters(slave, address, 1);
    }


    /**
     * Read multiple input registers
     * @param slave Slave address
     * @param startAddress Starting address
     * @param numberOfPoints Read the number of input registers
     * @throws ModbusError Modbus error
     */
    public void readInputRegisters(int slave, int startAddress, int numberOfPoints) throws ModbusError {
        byte[] sendBytes = execute(slave, ModbusFunction.READ_INPUT_REGISTERS, startAddress, numberOfPoints, 0, null);
        this.serialHelper.send(sendBytes);
    }
    //Read single input register
    public void readInputRegister(int slave, int address) throws ModbusError {
        readInputRegisters(slave, address, 1);
    }

    /**
     * Read multiple discrete input registers
     * @param slave Slave address
     * @param startAddress Starting address
     * @param numberOfPoints Read the number of discrete input registers
     * @throws ModbusError Modbus error
     */
    public void readDiscreteInputs(int slave, int startAddress, int numberOfPoints) throws ModbusError {
        byte[] sendBytes = execute(slave, ModbusFunction.READ_DISCRETE_INPUTS, startAddress, numberOfPoints, 0, null);
        this.serialHelper.send(sendBytes);
    }
    //Read a single discrete input register
    public void readDiscreteInput(int slave, int address) throws ModbusError {
        readDiscreteInputs(slave, address, 1);
    }

    /**
     * Write single coil register
     * @param slave Slave address
     * @param address Write register address
     * @param value Write value (true/false)
     * @throws ModbusError Modbus error
     */
    public void writeSingleCoil(int slave, int address, boolean value) throws ModbusError {
        byte[] sendBytes = execute(slave, ModbusFunction.WRITE_SINGLE_COIL, address, 1, value ? 1 : 0, null);
        this.serialHelper.send(sendBytes);
    }

    /**
     * Write a single holding register
     * @param slave Slave address
     * @param address Write register address
     * @param value Write value
     * @throws ModbusError Modbus error
     */
    public void writeSingleRegister(int slave, int address, int value) throws ModbusError {
        byte[] sendBytes = execute(slave, ModbusFunction.WRITE_SINGLE_REGISTER, address, 1, value, null);
        this.serialHelper.send(sendBytes);
    }

    /**
     *   Write multiple holding registers
     * @param slave Slave address
     * @param address Write register address
     * @param sCount Number of registers written
     * @param data Write data
     * @throws ModbusError
     */
    public void writeHoldingRegisters(int slave, int address, int sCount, int [] data) throws ModbusError {
        byte[] sendBytes = execute(slave, ModbusFunction.WRITE_HOLDING_REGISTERS, address, sCount, 0, data);
        this.serialHelper.send(sendBytes);
    }

    /**
     *   Write multiple bits
     * @param slave Slave address
     * @param address Write register address
     * @param bCount Number of registers written
     * @param data Write data {1,0}
     * @throws ModbusError
     */
    public void writeCoils(int slave, int address,int bCount, int [] data) throws ModbusError {
        byte[] sendBytes = execute(slave, ModbusFunction.WRITE_COILS, address, bCount, 0, data);
        this.serialHelper.send(sendBytes);
    }



    //Invert array
    public static int[] reverseArr(int[] arr) {
        int[] tem = new int[arr.length];
        for(int i=0; i<arr.length; i++) {
            tem[i] = arr[arr.length-1-i];
        }
        return tem;
    }

    //Convert int[1,0,0,1,1,0] array to decimal data
    public static int toDecimal(int[] data){
        int result = 0;
        if(data != null){
            StringBuilder sData = new StringBuilder();
            for (int d : data){
                sData.append(d);
            }
            try {
                result = Integer.parseInt(sData.toString(), 2);
            } catch (NumberFormatException e) {
                result = -1;
            }

        }
        return result;
    }

}

public class ModbusUtil {

    ModbusRtuMaster modbusRtuMaster;
    SerialHelper serialHelper;

    public void start() {
        try {

            //Initialize the SerialHelper object and set the serial port name and baud rate
            serialHelper = new SerialHelper("/dev/ttySAC0", 115200) {
                @Override
                protected void onDataReceived(ComBean paramComBean) {
                    //Process the received data according to their own business
                    L.i("Data 1==" + Arrays.toString(paramComBean.bRec) + "===" + paramComBean.bRec.length + "==" + paramComBean.bRec[0] + "==" + paramComBean.bRec[1]);
                    //[1, 3, 0, 1, 0, 1, -43, -54]
                    //If it is negative, the decimal result is 256 + negative, such as 256 + (- 54) = 202

					//Here you need to process the received data. Let me give an example. After receiving the data, return a data,
                    Of course, the official launch must be replied according to the response message rules
                    new Thread(() -> {
                        try {
                            modbusRtuMaster.writeSingleRegister(1, 1, 3);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }).start();
                }
            };

            /*
             * The default BaseStickPackageHelper expands the received data to 64 bits, which is generally less than that
             * I reset the number of adaptive data bits here
             * Here, 64 bits are changed to adaptive bits
             */
            serialHelper.setStickPackageHelper(is -> {
                try {
                    int available = is.available();
                    if (available > 0) {
                        byte[] buffer = new byte[available];
                        int size = is.read(buffer);
                        if (size > 0) {
                            return buffer;
                        }
                    } else {
                        SystemClock.sleep(50);
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            });

            new Thread(() -> {
                try {
                    serialHelper.open();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            modbusRtuMaster = new ModbusRtuMaster(serialHelper);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
use
ModbusUtil m = new ModbusUtil();
        m.start();

We can directly call start() of ModbusUtil to open the serial port. Note that / dev/ttySAC0 is the serial port file name and 115200 is the baud rate. Set the serial port parameters and use serialhelper Open () method can open the serial port, and then send data through the file stream. Combined with modbus protocol, we need to send a message and write the data into the output stream. For example, we read the coil. The message format is


That is: slave station address function code starting address coil quantity check code
Note that the starting address, coil number and check code are 16 bits, and the others are 8 bits
Here, the ByteArrayWriter class has encapsulated the method for us. Just write writeInt8 or writeInt16.
Then we use mobdus debugging tool to test.
Using the above source code, you can debug the following results

Here, after receiving the data, I replied to modbusrtumaster writeSingleRegister(1, 1, 3);, Then the receiving end receives 03. So far, the transmission and reception are completed. In addition, it should be noted that when others send data to you, you need to reply according to the format of response message.

Keywords: Android

Added by PatriotXCountry on Fri, 18 Feb 2022 06:37:48 +0200