Esempio n. 1
0
    public byte[] msgTransaction(byte[] msg) throws ModbusProtocolException {
      byte[] cmd = null;

      if (m_txMode == ModbusTransmissionMode.RTU_MODE) {
        cmd = new byte[msg.length + 2];
        for (int i = 0; i < msg.length; i++) cmd[i] = msg[i];
        // Add crc calculation to end of message
        int crc = Crc16.getCrc16(msg, msg.length, 0x0ffff);
        cmd[msg.length] = (byte) crc;
        cmd[msg.length + 1] = (byte) (crc >> 8);
      } else
        throw new ModbusProtocolException(
            ModbusProtocolErrorCode.METHOD_NOT_SUPPORTED, "Only RTU over TCP/IP supported");

      // Check connection status and connect
      connect();
      if (!connected)
        throw new ModbusProtocolException(
            ModbusProtocolErrorCode.TRANSACTION_FAILURE, "Cannot transact on closed socket");

      // Send the message
      try {
        // flush input
        while (inputStream.available() > 0) inputStream.read();
        // send all data
        outputStream.write(cmd, 0, cmd.length);
        outputStream.flush();
      } catch (IOException e) {
        // Assume this means the socket is closed...make sure it is
        s_logger.error("Socket disconnect in send: " + e);
        disconnect();
        throw new ModbusProtocolException(
            ModbusProtocolErrorCode.TRANSACTION_FAILURE, "Send failure: " + e.getMessage());
      }

      // wait for and process response
      byte[] response = new byte[262]; // response buffer
      int respIndex = 0;
      int minimumLength = 5; // default minimum message length
      while (true) {
        while (respIndex < minimumLength) {
          try {
            socket.setSoTimeout(m_respTout);
            int resp = inputStream.read(response, respIndex, minimumLength - respIndex);
            if (resp > 0) {
              respIndex += resp;
            } else {
              s_logger.error("Socket disconnect in recv");
              disconnect();
              throw new ModbusProtocolException(
                  ModbusProtocolErrorCode.TRANSACTION_FAILURE, "Recv failure");
            }
          } catch (SocketTimeoutException e) {
            String failMsg = "Recv timeout";
            s_logger.warn(failMsg);
            throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE, failMsg);
          } catch (IOException e) {
            s_logger.error("Socket disconnect in recv: " + e);
            disconnect();
            throw new ModbusProtocolException(
                ModbusProtocolErrorCode.TRANSACTION_FAILURE, "Recv failure");
          }
        }

        // Check first for an Exception response
        if ((response[1] & 0x80) == 0x80) {
          if (Crc16.getCrc16(response, 5, 0xffff) == 0)
            throw new ModbusProtocolException(
                ModbusProtocolErrorCode.TRANSACTION_FAILURE,
                "Resp exception = " + Byte.toString(response[2]));
        } else {
          // then check for a valid message
          switch (response[1]) {
            case ModbusFunctionCodes.FORCE_SINGLE_COIL:
            case ModbusFunctionCodes.PRESET_SINGLE_REG:
            case ModbusFunctionCodes.FORCE_MULTIPLE_COILS:
            case ModbusFunctionCodes.PRESET_MULTIPLE_REGS:
              if (respIndex < 8)
                // wait for more data
                minimumLength = 8;
              else if (Crc16.getCrc16(response, 8, 0xffff) == 0) {
                byte[] ret = new byte[8];
                for (int i = 0; i < 8; i++) ret[i] = response[i];
                return ret;
              }
              break;
            case ModbusFunctionCodes.READ_COIL_STATUS:
            case ModbusFunctionCodes.READ_INPUT_STATUS:
            case ModbusFunctionCodes.READ_INPUT_REGS:
            case ModbusFunctionCodes.READ_HOLDING_REGS:
              int byteCnt = (response[2] & 0xff) + 5;
              if (respIndex < byteCnt)
                // wait for more data
                minimumLength = byteCnt;
              else if (Crc16.getCrc16(response, byteCnt, 0xffff) == 0) {
                byte[] ret = new byte[byteCnt];
                for (int i = 0; i < byteCnt; i++) ret[i] = response[i];
                return ret;
              }
          }
        }

        /*
         * if required length then must have failed, drop first byte and
         * try again
         */
        if (respIndex >= minimumLength)
          throw new ModbusProtocolException(
              ModbusProtocolErrorCode.TRANSACTION_FAILURE, "Error in recv");
      }
    }
Esempio n. 2
0
    /**
     * msgTransaction must be called with a byte array having two extra bytes for the CRC. It will
     * return a byte array of the response to the message. Validation will include checking the CRC
     * and verifying the command matches.
     */
    public byte[] msgTransaction(byte[] msg) throws ModbusProtocolException {

      byte[] cmd = null;

      if (m_txMode == ModbusTransmissionMode.RTU_MODE) {
        cmd = new byte[msg.length + 2];
        for (int i = 0; i < msg.length; i++) cmd[i] = msg[i];
        // Add crc calculation to end of message
        int crc = Crc16.getCrc16(msg, msg.length, 0x0ffff);
        cmd[msg.length] = (byte) crc;
        cmd[msg.length + 1] = (byte) (crc >> 8);
      } else if (m_txMode == ModbusTransmissionMode.ASCII_MODE) {
        cmd = convertCommandToAscii(msg);
      }

      // Send the message
      try {
        synchronized (out) {
          synchronized (in) {
            // flush input
            if (m_serial485) switchRX();
            while (in.available() > 0) in.read();
            // send all data
            if (m_serial485) switchTX();
            out.write(cmd, 0, cmd.length);
            out.flush();
            // outputStream.waitAllSent(respTout);

            // wait for and process response
            if (m_serial485) switchRX();
            byte[] response = new byte[262]; // response buffer
            int respIndex = 0;
            int minimumLength = 5; // default minimum message length
            if (m_txMode == ModbusTransmissionMode.ASCII_MODE) minimumLength = 11;
            int timeOut = m_respTout;
            for (int maxLoop = 0; maxLoop < 1000; maxLoop++) {
              boolean endFrame = false;
              // while (respIndex < minimumLength) {
              while (!endFrame) {
                long start = System.currentTimeMillis();
                while (in.available() == 0) {
                  try {
                    Thread.sleep(5); // avoid a high cpu load
                  } catch (InterruptedException e) {
                    throw new ModbusProtocolException(
                        ModbusProtocolErrorCode.TRANSACTION_FAILURE, "Thread interrupted");
                  }

                  long elapsed = System.currentTimeMillis() - start;
                  if (elapsed > timeOut) {
                    String failMsg = "Recv timeout";
                    s_logger.warn(
                        failMsg
                            + " : "
                            + elapsed
                            + " minimumLength="
                            + minimumLength
                            + " respIndex="
                            + respIndex);
                    throw new ModbusProtocolException(
                        ModbusProtocolErrorCode.RESPONSE_TIMEOUT, failMsg);
                  }
                }
                // address byte must match first
                if (respIndex == 0) {
                  if (m_txMode == ModbusTransmissionMode.ASCII_MODE) {
                    if ((response[0] = (byte) in.read()) == ':') respIndex++;
                  } else {
                    if ((response[0] = (byte) in.read()) == msg[0]) respIndex++;
                  }
                } else response[respIndex++] = (byte) in.read();

                if (m_txMode == ModbusTransmissionMode.RTU_MODE) {
                  timeOut = 100; // move to character timeout
                  if (respIndex >= minimumLength) endFrame = true;
                } else {
                  if ((response[respIndex - 1] == 10) && (response[respIndex - 2] == 13))
                    endFrame = true;
                }
              }
              // if ASCII mode convert response
              if (m_txMode == ModbusTransmissionMode.ASCII_MODE) {
                byte lrcRec = asciiLrcCalc(response, respIndex);
                response = convertAsciiResponseToBin(response, respIndex);
                byte lrcCalc = (byte) binLrcCalc(response);
                if (lrcRec != lrcCalc)
                  throw new ModbusProtocolException(
                      ModbusProtocolErrorCode.TRANSACTION_FAILURE, "Bad LRC");
              }

              // Check first for an Exception response
              if ((response[1] & 0x80) == 0x80) {
                if ((m_txMode == ModbusTransmissionMode.ASCII_MODE)
                    || (Crc16.getCrc16(response, 5, 0xffff) == 0))
                  throw new ModbusProtocolException(
                      ModbusProtocolErrorCode.TRANSACTION_FAILURE,
                      "Exception response = " + Byte.toString(response[2]));
              } else {
                // then check for a valid message
                switch (response[1]) {
                  case ModbusFunctionCodes.FORCE_SINGLE_COIL:
                  case ModbusFunctionCodes.PRESET_SINGLE_REG:
                  case ModbusFunctionCodes.FORCE_MULTIPLE_COILS:
                  case ModbusFunctionCodes.PRESET_MULTIPLE_REGS:
                    if (respIndex < 8)
                      // wait for more data
                      minimumLength = 8;
                    else if ((m_txMode == ModbusTransmissionMode.ASCII_MODE)
                        || (Crc16.getCrc16(response, 8, 0xffff) == 0)) {
                      byte[] ret = new byte[6];
                      for (int i = 0; i < 6; i++) ret[i] = response[i];
                      return ret;
                    }
                    break;
                  case ModbusFunctionCodes.READ_COIL_STATUS:
                  case ModbusFunctionCodes.READ_INPUT_STATUS:
                  case ModbusFunctionCodes.READ_INPUT_REGS:
                  case ModbusFunctionCodes.READ_HOLDING_REGS:
                    int byteCnt;
                    if ((m_txMode == ModbusTransmissionMode.ASCII_MODE))
                      byteCnt = (response[2] & 0xff) + 3;
                    else byteCnt = (response[2] & 0xff) + 5;
                    if (respIndex < byteCnt)
                      // wait for more data
                      minimumLength = byteCnt;
                    else if ((m_txMode == ModbusTransmissionMode.ASCII_MODE)
                        || (Crc16.getCrc16(response, byteCnt, 0xffff) == 0)) {
                      byte[] ret = new byte[byteCnt];
                      for (int i = 0; i < byteCnt; i++) ret[i] = response[i];
                      return ret;
                    }
                }
              }

              /*
               * if required length then must have failed, drop
               * first byte and try again
               */
              if (respIndex >= minimumLength) {
                respIndex--;
                for (int i = 0; i < respIndex; i++) response[i] = response[i + 1];
                minimumLength = 5; // reset minimum length
              }
            }
          }
        }
      } catch (IOException e) {
        // e.printStackTrace();
        throw new ModbusProtocolException(
            ModbusProtocolErrorCode.TRANSACTION_FAILURE, e.getMessage());
      }
      throw new ModbusProtocolException(
          ModbusProtocolErrorCode.TRANSACTION_FAILURE, "Too much activity on recv line");
    }