Package modbuspal.link

Source Code of modbuspal.link.ModbusSerialLink$CommPortList

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package modbuspal.link;

import java.io.IOException;
import java.util.Enumeration;
import gnu.io.*;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.TooManyListenersException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ComboBoxModel;
import javax.swing.event.ListDataListener;
import static modbuspal.link.ModbusSlaveProcessor.makeExceptionResponse;
import static modbuspal.main.ModbusConst.XC_SLAVE_DEVICE_FAILURE;
import modbuspal.main.ModbusPalProject;
import modbuspal.master.ModbusMasterRequest;
import modbuspal.slave.ModbusSlaveAddress;
import modbuspal.toolkit.ModbusTools;
import modbuspal.toolkit.SystemTools;

/**
* The serial link waits for incoming requests from a COM port
* @author nnovic
*/
public class ModbusSerialLink
extends ModbusSlaveProcessor
implements ModbusLink, Runnable, SerialPortEventListener
{
    /** identifier to specify that there is no parity for the serial communication */
    public static final int PARITY_NONE = 0;
   
    /** identifier to specify that the odd parity must be used for the serial communication */
    public static final int PARITY_ODD = 1;
   
    /** identifier to specify that the even parity must be used for the serial communication */
    public static final int PARITY_EVEN = 2;

    public static final int STOP_BITS_1 = 0;

    public static final int STOP_BITS_1_5 = 1;

    public static final int STOP_BITS_2 = 2;
   
    private static ArrayList<CommPortIdentifier> commPorts = new ArrayList<CommPortIdentifier>();

    /**
     * This method will check that the specified com port actually exists.
     * @param comId a string containing a COM port name.
     * @return true if the COM port exists.
     */
    public static boolean exists(String comId)
    {
        for(int i=0; i<commPorts.size(); i++)
        {
            CommPortIdentifier commPort = commPorts.get(i);
            if( commPort.getName().compareTo(comId)==0 )
            {
                return true;
            }
        }
        return false;
    }


    /**
     *
     */
    public static class CommPortList
    implements ComboBoxModel
    {
        private Object selectedItem;
        CommPortList()
        {
            if( commPorts.size()>=1 )
            {
                selectedItem = commPorts.get(0).getName();
            }
        }
        @Override
        public int getSize()
        {
            return commPorts.size();
        }
        @Override
        public Object getElementAt(int index)
        {
            return commPorts.get(index).getName();
        }
        @Override
        public void addListDataListener(ListDataListener l)
        {
        }
        @Override
        public void removeListDataListener(ListDataListener l)
        {
        }
        @Override
        public void setSelectedItem(Object anItem)
        {
            selectedItem = anItem;
        }
        @Override
        public Object getSelectedItem()
        {
            return selectedItem;
        }
    }

    /**
     * Returns the list of available COM ports on the host system.
     * @return list of available COM ports
     */
    public static CommPortList getListOfCommPorts()
    {
        return new CommPortList();
    }

       
    private static boolean installOnWindows()
    throws IOException
    {
        System.out.println("Install RXTX on Windows...");
       
        String jrePath = System.getProperty("java.home");
        System.out.printf("java.home returns \"%s\"\r\n", jrePath);
       
        // Copy RXTXcomm.jar ---> <JAVA_HOME>\jre\lib\ext
        // Copy rxtxSerial.dll ---> <JAVA_HOME>\jre\bin
        // Copy rxtxParallel.dll ---> <JAVA_HOME>\jre\bin
       
        if( SystemTools.IsWindows64bits() )
        {
            System.out.println("64-bit architecture detected...");
            SystemTools.Install("rxtx/win-x64/RXTXcomm.jar", new File(jrePath, "lib/ext/RXTXcomm.jar") );
            SystemTools.Install("rxtx/win-x64/rxtxParallel.dll", new File(jrePath, "bin/rxtxParallel.dll") );
            SystemTools.Install("rxtx/win-x64/rxtxSerial.dll", new File(jrePath, "bin/rxtxSerial.dll") );
        }
        else
        {
            System.out.println("32-bit architecture detected...");
            SystemTools.Install("rxtx/win-x86/RXTXcomm.jar", new File(jrePath, "lib/ext/RXTXcomm.jar") );
            SystemTools.Install("rxtx/win-x86/rxtxParallel.dll", new File(jrePath, "bin/rxtxParallel.dll") );
            SystemTools.Install("rxtx/win-x86/rxtxSerial.dll", new File(jrePath, "bin/rxtxSerial.dll") );           
        }
           
       
        return false;
    }
   
   
    public static boolean install()
    {
        System.out.println("---------------------------------------------");
        System.out.println("Installing RXTX component...");
        System.out.println("---------------------------------------------");
       
        try
        {
            if( SystemTools.IsWindowsHost() == true )
            {
                return installOnWindows();
            }
            return false;
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
            return false;
        }
    }
   
    /**
     * Setup the RXTX library and scan the available COM ports
     */
    public static boolean enumerate()
    {
        try
        {
            Enumeration portList = CommPortIdentifier.getPortIdentifiers();
            while( portList.hasMoreElements() )
            {
                CommPortIdentifier com = (CommPortIdentifier)portList.nextElement();
                if( com.getPortType()==CommPortIdentifier.PORT_SERIAL )
                {
                    System.out.println("Found "+com.getName() );
                    commPorts.add(com);
                }
            }
            return true;
        }
        catch(Exception ex)
        {
            return false;
        }
    }
    private int serialStopBits;
    private SerialPort serialPort;
    private int baudrate;
    private InputStream input;
    private OutputStream output;
    private boolean executeThread=false;
    private Thread serverThread;
    private int serialParity;
    private int flowControl;
    private ModbusLinkListener listener = null;

    /**
     * Creates a new instance of ModbusSerialLink.
     * @param mpp the modbuspal project that holds the slaves information
     * @param index index of the COM port to sue for communication
     * @param speed baudrate of the COM port
     * @param parity parity of the communication
     * @param xonxoff enables or disables XON/XOFF
     * @param rtscts enables or disables RTS/CTS
     * @throws PortInUseException
     * @throws ClassCastException
     */
    public ModbusSerialLink(ModbusPalProject mpp, int index, int speed, int parity, int stopBits, boolean xonxoff, boolean rtscts)
    throws PortInUseException, ClassCastException
    {
        super(mpp);

        CommPortIdentifier comm = commPorts.get(index);
        serialPort = (SerialPort)(comm.open("MODBUSPAL",3000));
        baudrate = speed;

        switch(parity)
        {
            case PARITY_NONE:
                serialParity=SerialPort.PARITY_NONE;
                break;
            case PARITY_ODD:
                serialParity=SerialPort.PARITY_ODD;
                break;
            default:
            case PARITY_EVEN:
                serialParity=SerialPort.PARITY_EVEN;
                break;
        }

        switch(stopBits)
        {
            default:
            case STOP_BITS_1:
                serialStopBits=SerialPort.STOPBITS_1;
                break;
            case STOP_BITS_1_5:
                serialStopBits=SerialPort.STOPBITS_1_5;
                break;
            case STOP_BITS_2:
                serialStopBits=SerialPort.STOPBITS_2;
                break;
        }
       
        flowControl = SerialPort.FLOWCONTROL_NONE;
        if( xonxoff==true )
        {
            flowControl |= SerialPort.FLOWCONTROL_XONXOFF_IN;
            flowControl |= SerialPort.FLOWCONTROL_XONXOFF_OUT;
        }
        if( rtscts==true )
        {
            flowControl |= SerialPort.FLOWCONTROL_RTSCTS_IN;
            flowControl |= SerialPort.FLOWCONTROL_RTSCTS_OUT;
        }
    }

    @Override
    public void start(ModbusLinkListener l)
    throws IOException
    {
        listener = l;

        try
        {
            serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8, serialStopBits, serialParity);
            input = serialPort.getInputStream();
            output = serialPort.getOutputStream();
            serialPort.addEventListener(this);
            serialPort.notifyOnDataAvailable(true);
            System.out.println("Connected to com port");
        }
        catch( TooManyListenersException ex)
        {
            throw new RuntimeException(ex);
        }
        catch (UnsupportedCommOperationException ex)
        {
            throw new RuntimeException(ex);
        }

        executeThread = true;
        serverThread = new Thread(this,"serial link");
        serverThread.start();
    }


    @Override
    public void stop()
    {
        executeThread = false;
        serverThread.interrupt();

        try
        {
            input.close();
        }
        catch (IOException ex)
        {
            Logger.getLogger(ModbusSerialLink.class.getName()).log(Level.SEVERE, null, ex);
        }

        try
        {
            output.close();
        }
        catch (IOException ex)
        {
            Logger.getLogger(ModbusSerialLink.class.getName()).log(Level.SEVERE, null, ex);
        }
       
        serialPort.close();

        try
        {
            serverThread.join();
        }
        catch (InterruptedException ex)
        {
            Logger.getLogger(ModbusTcpIpLink.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally
        {
            serverThread = null;
        }
    }

    @Override
    public void serialEvent(SerialPortEvent arg0)
    {
        synchronized(input)
        {
            input.notify();
        }
    }

    static int computeCRC(byte[] buffer, int offset, int length)
    {
        // Load a 16–bit register with FFFF hex (all 1’s). This is the CRC
        // register.
        int CRC = 0xFFFF;

        for( int i=0; i<length; i++ )
        {
            // Exclusive OR the first 8–bit byte of the message with the
            // low–order byte of the 16–bit CRC register, putting the result
            // in the CRC register.
            int b = buffer[offset+i] & 0xFF;
            CRC = (CRC ^ b) & 0xFFFF;
           
            for( int j=0; j<8; j++ )
            {
                int LSB = CRC & 1;
                CRC = (CRC >> 1) ;
                if( LSB==1 )
                {
                    CRC = (CRC ^ 0xA001) & 0xFFFF;
                }
            }
        }
        return CRC;
    }

    @Override
    public void run()
    {
        byte buffer[] = new byte[256];
        System.out.println("Start ModbusSerialLink");

        while(executeThread == true)
        {
            try
            {
                // wait until a notification is issued by the SerialEvent
                // callback
                synchronized(input)
                {
                    input.wait(1000);
                }

                // if some data is available then:
                if( input.available() >= 1 )
                {
                    // read all available data
                    int totalLen = input.read(buffer);

                    // read slave address (it is the first byte)
                    int slaveID = ModbusTools.getUint8(buffer,0);

                    // read crc value (located in the last two bytes
                    int crcLSB = ModbusTools.getUint8(buffer, totalLen-2);
                    int crcMSB = ModbusTools.getUint8(buffer, totalLen-1);
                    int receivedCRC = crcMSB * 256 + crcLSB;

                    // compute crc between slave address (included) and crc (excluded)
                    int computedCRC = computeCRC(buffer,0,totalLen-2);

                    int pduLength = totalLen - 3; // 1 for slave address, and 2 for CRC

                    // if CRC are ok, then process the pdu
                    if( receivedCRC == computedCRC )
                    {
                        //System.out.println("read "+ totalLen + " bytes");
                        pduLength = processPDU(new ModbusSlaveAddress(slaveID), buffer, 1, pduLength);
                    }

                    else
                    {
                        // handle CRC error with exception code
                        pduLength = makeExceptionResponse(XC_SLAVE_DEVICE_FAILURE, buffer, 1);
                    }

                    // if the output pdu length is positive, then send the content
                    // of the buffer
                    if( pduLength > 0 )
                    {
                        totalLen = 1+ pduLength + 2; // 1 for slave address, and 2 for CRC

                        // compute crc of outgoing reply
                        int outputCRC = computeCRC(buffer,0,totalLen-2);

                        // low order byte of the CRC must be transmitted first
                        buffer[totalLen-2] = (byte)(outputCRC & 0xFF);
                        buffer[totalLen-1] = (byte)((outputCRC>>8) & 0xFF);

                        // write content of buffer into the output stream
                        output.write(buffer, 0, totalLen);
                        output.flush();
                    }
                }
            }
            catch( InterruptedException ex)
            {
                // not an error
            }
            catch (IOException ex)
            {
                if( Thread.interrupted() == false )
                {
                    Logger.getLogger(ModbusSerialLink.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        System.out.println("Stop ModbusSerialLink");
        listener.linkBroken();
        listener = null;
    }


    @Override
    public void startMaster(ModbusLinkListener l)
    throws IOException
    {
        listener = l;

        try
        {
            serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8, serialStopBits, serialParity);
            input = serialPort.getInputStream();
            output = serialPort.getOutputStream();
            serialPort.addEventListener(this);
            serialPort.notifyOnDataAvailable(true);
            System.out.println("Connected to com port");
        }
        catch( TooManyListenersException ex)
        {
            throw new RuntimeException(ex);
        }
        catch (UnsupportedCommOperationException ex)
        {
            throw new RuntimeException(ex);
        }
    }

   
    @Override
    public void stopMaster()
    {
        try
        {
            input.close();
        }
        catch (IOException ex)
        {
            Logger.getLogger(ModbusSerialLink.class.getName()).log(Level.SEVERE, null, ex);
        }

        try
        {
            output.close();
        }
        catch (IOException ex)
        {
            Logger.getLogger(ModbusSerialLink.class.getName()).log(Level.SEVERE, null, ex);
        }
       
        serialPort.close();
    }

    @Override
    public void execute(ModbusSlaveAddress dst, ModbusMasterRequest req, int timeout)
    throws IOException
    {
        byte buffer[] = new byte[2048];
       
        // genete PDU of the request, start at offset 1
        // (leave room for header and footer).
        int length = buildPDU(req, dst, buffer, 1);
       
        // prepend slave address
        ModbusTools.setUint8(buffer, 0, dst.getRtuAddress());
       
        // compute CRC
        int totalLen = 1+ length + 2; // 1 for slave address, and 2 for CRC
        int outputCRC = computeCRC(buffer,0,totalLen-2);
        buffer[totalLen-2] = (byte)(outputCRC & 0xFF);
        buffer[totalLen-1] = (byte)((outputCRC>>8) & 0xFF);
               
        // send request
        output.write(buffer, 0, totalLen);
        output.flush();
               
        // wait for reply
        synchronized(input)
        {
            try
            {
                input.wait(timeout);
            }
            catch (InterruptedException ex)
            {
                Logger.getLogger(ModbusSerialLink.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        // if some data is available then:
        if( input.available() >= 3 )
        {
            // read all available data
            totalLen = input.read(buffer);

            // read slave address (it is the first byte)
            int slaveID = ModbusTools.getUint8(buffer,0);

            // read crc value (located in the last two bytes
            int crcLSB = ModbusTools.getUint8(buffer, totalLen-2);
            int crcMSB = ModbusTools.getUint8(buffer, totalLen-1);
            int receivedCRC = crcMSB * 256 + crcLSB;

            // compute crc between slave address (included) and crc (excluded)
            int computedCRC = computeCRC(buffer,0,totalLen-2);

            int pduLength = totalLen - 3; // 1 for slave address, and 2 for CRC

            // if CRC are ok, then process the pdu
            if( receivedCRC == computedCRC )
            {
                //System.out.println("read "+ totalLen + " bytes");
                //pduLength = processPDU(new ModbusSlaveAddress(slaveID), buffer, 1, pduLength);
                processPDU(req, dst, buffer, 1, totalLen - 3);
            }

            else
            {
                // handle CRC error with exception code
                //pduLength = makeExceptionResponse(XC_SLAVE_DEVICE_FAILURE, buffer, 1);
            }
        }
    }
}
TOP

Related Classes of modbuspal.link.ModbusSerialLink$CommPortList

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.