package rs232comm;

// Metex M-3660D CommunicationClass
// von Tobias Kölligan und André Knaub
// basierend auf Beispielen von rxtx.org und java.sun.com
// 1. LEA - 25.09.2006 - 29.09.2006 - Semester 2
// EPT/PRG Feuchtigkeitssensor
// betreuender Dozent: Herr Lohre

import gnu.io.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DecimalFormat;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class TwoWaySerialComm
{
	// Variablen deklarieren
	CommPort commPort;
	SerialPort serialPort;
	CommPortIdentifier portIdentifier;
	String frq = "";
	int relh;
	int herz;
	JLabel freq;
	JLabel relhum;
	JLabel freqlabel;
	JLabel relhumlabel;
	JLabel empty;
	Brett fl1;
		
	// DecimalFormat zum formatieren von Zahlen
	DecimalFormat form = new DecimalFormat("#,##0.0#");
	
	// Konstruktor, Aufruf der Elternklasse
    TwoWaySerialComm()
    {
		super();
    }
    
    // connect() Methode zum Verbindungsaufbau mit RS232 Schnittstelle
    // Port wählen und Übertragungsdaten festlegen
    // Schreiben und Lesen starten
    void connect ( String portName ) throws Exception
    {
        try
        {
        	// Port Identifikation finden
    	   	portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
    	   	
    	   	// Port in gebrauch?
	        if ( portIdentifier.isCurrentlyOwned() )
	        {
	            System.out.println("Error: Port is currently in use");
	        }
	        else
	        {
	        	// Port öffnen (Timeout 2000ms)
	            commPort = portIdentifier.open(this.getClass().getName(),2000);
	            
	            if ( commPort instanceof SerialPort )
	            {
	            	// Verbindungsparameter setzen
	            	// BaudRate, Datenbits, Stopbits, Parity?
	                serialPort = (SerialPort) commPort;
	                serialPort.setSerialPortParams(1200,SerialPort.DATABITS_7,SerialPort.STOPBITS_2,SerialPort.PARITY_NONE);
	                
	                // Input- und OutputStreams instanziieren
	                InputStream in = serialPort.getInputStream();
	                OutputStream out = serialPort.getOutputStream();
	                
	                // 2 Threads starten für Schreiben und Lesen
	                // Wichtig! Erst Schreiben und dann Lesen (siehe Metex DMM Handbuch)
	                (new Thread(new SerialWriter(out))).start();
	                (new Thread(new SerialReader(in))).start();                
	
	            }
	            else
	            {
	                System.out.println("Error: Only serial ports are handled by this example.");
	            }
	        } 
	        
        }catch(Exception e)
        {
        
        	System.out.println("Port in use!");
        	
        }
    }
    
    // Klasse zum Lesen von Daten der RS232 Schnittstelle
    class SerialReader extends JFrame implements Runnable 
    {
    	InputStream in;
    	
    	// InputStream übergeben
        public SerialReader ( InputStream in )
        {
            this.in = in;
        }
        
        // run() Methode des Threads
        public void run ()
        {
	  
        	// Anwendung schliessen wenn auf [x] gedrückt wird
        	class WindowLauscher extends WindowAdapter {
				
			    public void windowClosing(WindowEvent e) {

			    	// Port schliessen, WICHTIG damit
			    	// keine PortInUse Exception auftritt
			    	commPort.close();
			        System.exit(0);
			        
			    }
			    
			}
    	
        	// grafisches Layout festlegen
        	getContentPane().setLayout(new GridLayout(2,3,0,0));
        	getContentPane().setBackground(Color.WHITE);        	
        	
        	// JLabel anlegen
        	freqlabel = new JLabel("Frequenz:  ",JLabel.RIGHT);
        	relhumlabel = new JLabel("rel. Feuchtigkeit:  ",JLabel.RIGHT);
        	empty = new JLabel("<html><body>Der Messbalken zeigt die Veränderung<br>der Frequenz.</body></html>");
        	
        	// die beiden "Ausgabelabels" anlegen
        	freq = new JLabel();
        	relhum = new JLabel();
        	
        	// Schrift ändern
        	freq.setFont(new Font("Verdana",Font.BOLD,25));
        	relhum.setFont(new Font("Verdana",Font.BOLD,25));
        	freqlabel.setFont(new Font("Verdana",Font.BOLD,25));
        	relhumlabel.setFont(new Font("Verdana",Font.BOLD,25));
        	
        	// Zeichenfläche anlegen
        	fl1 = new Brett();
        	        	
        	// JLabel zum JFrame Adden
        	getContentPane().add(freqlabel);
        	getContentPane().add(freq);
        	getContentPane().add(fl1);
        	getContentPane().add(relhumlabel);
        	getContentPane().add(relhum);
        	getContentPane().add(empty);
        	
        	
        	// JFrame Parameter festlegen
    		addWindowListener(new WindowLauscher());
    		setLocation(100,100);
    		setResizable(true);
    		pack();
    		setVisible(true);
        	
    		// Endlosschleife für den Thread + 2 Sekunden Pause
        	while(true){
        	   	
        		// Datenpuffer anlegen
        		byte[] buffer = new byte[14];
        		int len = -1;
        		        		
        		// Auslesen der Schnittstelle starten
        		try
        		{
        			
        			frq = "";
        			while ( ( len = this.in.read(buffer)) > 0 )
        			{
        				// Daten in Variable frq schreiben
        				frq += new String(buffer,0,len);
        			}       		

        			try{
        			
	        			// Herz aus String extrahieren
	        			herz = Integer.parseInt(frq.substring(6,9));
	       			        			
	        			// Formelanwendung zum bestimmen der rel. Feuchtigkeit
	        			// Messfühlerbereich 20% - 80%
	        			if(herz <= 2){
	        				
	        				relh = 20;
	        				
	        			}else if(herz > 2 && herz < 5){
	        				
	        				relh = 25 - ((int)(Math.round((5 - herz) / 0.3))); 
	        				
	        			}else if(herz > 5 && herz < 19){
	        				
	        				relh = 35 - ((int)(Math.round((19 - herz) / 1.4)));
	        				
	        			}else if(herz > 19 && herz < 65){
	        				
	        				relh = 45 - ((int)(Math.round((65 - herz) / 4.6)));
	        				
	        			}else if(herz > 65 && herz < 228){
	        				
	        				relh = 55 - ((int)(Math.round((228 - herz) / 16.3)));
	        				
	        			}else if(herz > 228 && herz < 796){
	        				
	        				relh = 65 - ((int)(Math.round((796 - herz) / 56.8)));
	        				
	        			}else if(herz >= 796){
	        				
	        				relh = 80;
	        				
	        			}
        			
        			}catch(Exception e)
        			{
        			
        				System.out.println();
        				
        			}
        			
        			// Datenformat anpassen und rel. Feuchtigkeit berechnen        			
        			try
        			{
        				// invokeLater() Methode als Workaround 
        				// da Swing NICHT threadsicher ist!
        				// Thread wird so in AWT-Thread geschoben und dort abgearbeitet
        				// siehe http://www.galileocomputing.de/openbook/javainsel5/javainsel15_032.htm
        				SwingUtilities.invokeLater(new Runnable()	
        				{		
        						public void run()			
        						{			
        							freq.setText(herz+" Hz");	
        							relhum.setText(relh+" %");
        							fl1.repaint();        							
        						}		
        				});
        			
        			}catch(Exception e)
        			{
        				
        				System.out.println("Datenlesefehler");
        				
        			}
            	
        			// Thread schlafen legen, danach gehts weiter, da Endlosschleife
	        		try 
	        		{
	        			Thread.sleep(2000);
	        			
	        		}catch(InterruptedException e)
	        		{
	        			
	        			System.out.println("Thread.sleep() Error");
	        			
	        		}
        		
        		}
        		catch ( IOException e )
	            {
	            	e.printStackTrace();
	            }
            	                        
        	}
           
        }
        
    }
        
    // Klasse zum Schreiben auf der RS232 Schnittstelle
    public static class SerialWriter implements Runnable 
    {
        OutputStream out;
        
        public SerialWriter ( OutputStream out )
        {
            this.out = out;
        }
        
        public void run ()
        {
            
        	while(true){
	        	
	        	try
	            {      
	            	// Wichtig! write() schreibt nur Integer Werte
	            	// Metex DMM benötigt 'D' zum senden der Daten
	            	// daher ein 'D' senden (als Integerwert)
	            	// Beachten: großes D, kleines D würde nicht funktionieren
	            	this.out.write((int)'D');
	            	
	            	// Thread schlafen legen, danach gehts weiter, da Endlosschleife
	        		try 
	        		{
	        			Thread.sleep(1000);
	        			
	        		}catch(InterruptedException e)
	        		{
	        			
	        			System.out.println("Thread.sleep() Error");
	        			
	        		}
        		
	                               
	            }
	            catch( IOException e )
	            {
	            	
	                e.printStackTrace();
	                
	            }
            
        	}
        }
    }
    
    // Canvas Klasse "Brett" zum Zeichnen
	public class Brett extends Canvas{
		
		// Konstruktor
		Brett(){
			
			// Hinter- und Vordergrundfarben setzen
			setBackground(Color.WHITE);
									
		}
		
		// Grafikklasse
		public void paint(Graphics g){
			
			// Farbe ändern
			g.setColor(new Color(255,100,100));
			g.fillRect(0, 10, (herz / 2), 10);
			
			
		}
		
		// Minimumgröße festlegen (überschreiben)
		public Dimension getMinimumSize(){
			
			// Breite, Höhe
			return new Dimension(100,0);
			
		}
		
		// Größe des Canvas festlegen mit Hilfe von getMinimumSize()
		public Dimension getPreferredSize(){
			
			return getMinimumSize();
			
		}
	
	}

    
    // main() Methode
    public static void main ( String[] args )
    {
        try
        {
        	// Verbindung herstellen zu COM1
            (new TwoWaySerialComm()).connect("COM1");
        }
        catch ( Exception e )
        {
            e.printStackTrace();
        }
    }
}
