1. 程式人生 > >JavaWeb 用於windows的串列埠資料讀取

JavaWeb 用於windows的串列埠資料讀取

串列埠資料讀取類,用於windows的串列埠資料讀取;

1.例如觀察者為羊,被觀察者為狼 ,模仿的場景為狼叫羊跑,可參考部落格:

https://blog.csdn.net/dada360778512/article/details/6977758

2.模擬串列埠傳輸資料,需要兩個工具,Virtual Serial Port Driver、串列埠除錯助手;可參考:

https://jingyan.baidu.com/article/046a7b3eae7028f9c27fa9f7.html

3.基於RXTX(提供串列埠和並口通訊)開源類庫對串列埠進行操作的。具體配置,詳見:

https://blog.csdn.net/liu4071325/article/details/53392218

必備外掛/工具包:
1.專案裡引用:  RXTXcomm.jar

2.windows伺服器需要以下三個檔案:
       \JDK目錄\jre\lib\ext ---> RXTXcomm.jar
      \JDK目錄\bin ---> rxtxParallel.dll 和 rxtxSerial.dll

2.Linux伺服器需要放置以下三個檔案

       \JDK目錄\jre\lib\ext ---> RXTXcomm.jar
      \JDK目錄\bin --->librxtxParallel.so 和 librxtxSerial.so

感謝分享!

程式碼:

1.建立被觀察者 SerialReader.java 

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Observable;
import java.util.TooManyListenersException;

/**
 * <p>串列埠資料讀取類,用於windows的串列埠資料讀取</p>
 * 
 * 宣告被觀察者SerialReader,繼承Observable<br/>
 * 觀察者,繼承Observer<br/>
 * 
 * Observer模式  主要是觀察者與被觀察者之間的關係。<br/>
 * 
 */
public class SerialReader extends Observable implements Runnable, SerialPortEventListener {
	static CommPortIdentifier portId;
	int delayRead = 200;
	int numBytes; // buffer中的實際資料位元組數
	private static byte[] readBuffer = new byte[4096]; // 4k的buffer空間,快取串列埠讀入的資料
	static Enumeration portList;
	InputStream inputStream;
	SerialPort serialPort;
	//宣告觀察者時,被指定的引數資訊
	HashMap serialParams;
	// 埠讀入資料事件觸發後,等待n毫秒後再讀取,以便讓資料一次性讀完
	public static final String PARAMS_DELAY = "delay read"; // 延時等待埠資料準備的時間
	public static final String PARAMS_TIMEOUT = "timeout"; // 超時時間
	public static final String PARAMS_PORT = "port name"; // 埠名稱
	public static final String PARAMS_DATABITS = "data bits"; // 資料位
	public static final String PARAMS_STOPBITS = "stop bits"; // 停止位
	public static final String PARAMS_PARITY = "parity"; // 奇偶校驗
	public static final String PARAMS_RATE = "rate"; // 波特率

	public SerialReader() {
	}

	/**
	 * 初始化埠操作的引數.
	 * 
	 * @see
	 */
	public SerialReader(HashMap params) {
		serialParams = params;
		init();
	}

	private void init() {
		try {
			// 引數初始化
			int timeout = Integer.parseInt(serialParams.get(PARAMS_TIMEOUT).toString());
			int rate = Integer.parseInt(serialParams.get(PARAMS_RATE).toString());
			int dataBits = Integer.parseInt(serialParams.get(PARAMS_DATABITS).toString());
			int stopBits = Integer.parseInt(serialParams.get(PARAMS_STOPBITS).toString());
			int parity = Integer.parseInt(serialParams.get(PARAMS_PARITY).toString());
			delayRead = Integer.parseInt(serialParams.get(PARAMS_DELAY).toString());
			String port = serialParams.get(PARAMS_PORT).toString();
			// 開啟埠
			portId = CommPortIdentifier.getPortIdentifier(port);
			EWeightConstant.IS_OPEN_PORT = true;
			serialPort = (SerialPort) portId.open("SerialReader", timeout);
			inputStream = serialPort.getInputStream();
			serialPort.addEventListener(this);// 註冊串列埠監聽
			serialPort.notifyOnDataAvailable(true);// 資料可用
			serialPort.setSerialPortParams(rate, dataBits, stopBits, parity);// 設定引數
		} catch (PortInUseException e) {
			// System.out.println("串列埠已經被佔用!");
			e.printStackTrace();
		} catch (TooManyListenersException e) {
			// System.out.println("串列埠監聽者過多!");
			e.printStackTrace();
		} catch (UnsupportedCommOperationException e) {
			// System.out.println("串列埠操作命令不支援!");
			e.printStackTrace();
		} catch (NoSuchPortException e) {
			// System.out.println("串列埠不存在!");
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		Thread readThread = new Thread(this);
		readThread.start();
	}

	public void run() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public void serialEvent(SerialPortEvent event) {
		try {
			// 等待1秒鐘讓串列埠把資料全部接收後在處理
			Thread.sleep(delayRead);
			// System.out.print("serialEvent[" + event.getEventType() + "] ");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		switch (event.getEventType()) {
		case SerialPortEvent.BI: // 10
		case SerialPortEvent.OE: // 7
		case SerialPortEvent.FE: // 9
		case SerialPortEvent.PE: // 8
		case SerialPortEvent.CD: // 6
		case SerialPortEvent.CTS: // 3
		case SerialPortEvent.DSR: // 4
		case SerialPortEvent.RI: // 5
		case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2
			break;
		case SerialPortEvent.DATA_AVAILABLE: // 1
			try {
				// 多次讀取,將所有資料讀入
				while (inputStream.available() > 0) {
					numBytes = inputStream.read(readBuffer);
				}
				// numBytes = inputStream.read(readBuffer);
				changeMessage(readBuffer, numBytes);
			} catch (IOException e) {
				e.printStackTrace();
			}
			break;
		}
	}

	// 通過observer pattern將收到的資料傳送給observer
	// 將buffer中的空位元組刪除後再發送更新訊息,通知觀察者
	private String temp1 = "";

	public void changeMessage(byte[] message, int length) {
		setChanged();
		byte[] temp = new byte[length];
		System.arraycopy(message, 0, temp, 0, length);
		// 判斷資料是否穩定,穩定則只監聽不執行更新資料
		if (!"".equals(temp1)) {
			if (!temp1.equals(new String(temp).trim())) {
				temp1 = new String(temp).trim();
				notifyObservers(temp);
				// System.out.println("msg[" + numBytes + "]: [" + new
				// String(temp).trim() +"]");
			}
		} else {
			temp1 = new String(temp).trim();
			notifyObservers(temp);
		}
	}
	/**
	 * 除錯用,獲取所有的串列埠
	 */
	static void listPorts() {
		Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
		while (portEnum.hasMoreElements()) {
			CommPortIdentifier portIdentifier = (CommPortIdentifier) portEnum.nextElement();
			System.out.println("串列埠名稱:"+portIdentifier.getName() + " - " +"串列埠型別:"+getPortTypeName(portIdentifier.getPortType()));
		}
	}

	/**
	 * 讀取所有串列埠名字
	 */
	public static String getPortName() {
		CommPortIdentifier portId;
		Enumeration en = CommPortIdentifier.getPortIdentifiers();
		while (en.hasMoreElements()) {
			portId = (CommPortIdentifier) en.nextElement();
			if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
				return portId.getName();
			}
		}
		return "";
	}

	/**
	 * 讀取所有串列埠名字
	 */
	public static void closePort() {
		CommPortIdentifier portId;
		Enumeration en = CommPortIdentifier.getPortIdentifiers();
		while (en.hasMoreElements()) {
			portId = (CommPortIdentifier) en.nextElement();
			if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {

			}
		}
	}

	static String getPortTypeName(int portType) {
		switch (portType) {
		case CommPortIdentifier.PORT_I2C:
			return "I2C";
		case CommPortIdentifier.PORT_PARALLEL:
			return "Parallel";
		case CommPortIdentifier.PORT_RAW:
			return "Raw";
		case CommPortIdentifier.PORT_RS485:
			return "RS485";
		case CommPortIdentifier.PORT_SERIAL:
			return "Serial";
		default:
			return "unknown type";
		}
	}

	public static HashSet<CommPortIdentifier> getAvailableSerialPorts() {
		HashSet<CommPortIdentifier> h = new HashSet<CommPortIdentifier>();
		Enumeration thePorts = CommPortIdentifier.getPortIdentifiers();
		while (thePorts.hasMoreElements()) {
			CommPortIdentifier com = (CommPortIdentifier) thePorts.nextElement();
			switch (com.getPortType()) {
			case CommPortIdentifier.PORT_SERIAL:
				try {
					CommPort thePort = com.open("CommUtil", 50);
					thePort.close();
					h.add(com);
				} catch (PortInUseException e) {
					// System.out.println("Port, " + com.getName()+ ", is in
					// use.");
				} catch (Exception e) {
					// System.out.println("Failed to open port " +
					// com.getName()+ e);
				}
			}
		}
		return h;
	}
}

2.建立觀察者CommDataObserver.java


import java.util.Observable;
import java.util.Observer;
/**
 * 觀察類,繼承Observer<br/>
 * 建立一個觀察類,該觀察類有自己的name名稱
 *
 */
public class CommDataObserver implements Observer {
	private String name;
	
	public CommDataObserver() {
	}

	public CommDataObserver(String name) {
		this.name = name;
	}
	/**
	 * 監控串列埠,獲取串列埠資料
	 */
	public void update(Observable o, Object arg) {
		//獲取串列埠返回資料
		String weight = new String((byte[]) arg).trim();
		//將獲取到的資料,賦值到全域性變數裡,以便可以呼叫該資料
		EWeightConstant.GOOD_WEIGHT = weight;
				
		//testing  start 根據串列埠型別不同,返回的資料格式也不盡相同,此處除錯列印而已 {{
		System.out.println("weight="+weight);
		StringBuilder sb = new StringBuilder(weight);// 0.000或者00.000
		sb.insert(weight.length() - 3, ".");
		System.out.println(sb.toString() + "kg");
		//testing  end }}
		
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

3.初始化埠資料,並建立被觀察者和觀察者,並加入觀察GetWeightUtil.java


import java.util.HashMap;

import gnu.io.SerialPort;
/**
 * 獲取串列埠工具類
 * 此處宣告觀察者和被觀察者
 */
public class GetWeightUtil {
	
	/**
	 * 串列埠設定, 初始化埠資料
	 * @param com 埠
	 */
	public static void comConfig(String com) {
		//儲存埠資料
		HashMap<String, Comparable> params = new HashMap<String, Comparable>();
		// 埠名稱
		params.put(SerialReader.PARAMS_PORT, com);
		// 波特率
		params.put(SerialReader.PARAMS_RATE, 9600);
		// 裝置超時時間 1秒
		params.put(SerialReader.PARAMS_TIMEOUT, 1000); 
		// 埠資料準備時間 1秒
		params.put(SerialReader.PARAMS_DELAY, 200); 
		// 資料位
		params.put(SerialReader.PARAMS_DATABITS, SerialPort.DATABITS_8); 
		// 停止位
		params.put(SerialReader.PARAMS_STOPBITS, SerialPort.STOPBITS_1); 
		// 無奇偶校驗
		params.put(SerialReader.PARAMS_PARITY, SerialPort.PARITY_NONE); 
		//建立被觀察者
		SerialReader serialReader = new SerialReader(params);
		//建立觀察者
		CommDataObserver obServer = new CommDataObserver("電子秤");
		//新增一個觀察者,加入觀察
		serialReader.addObserver(obServer);
		
		//TODO 除錯用,輸出到控制檯 顯示所有串列埠號
		SerialReader.listPorts();
	}
	
	public static void main(String[] args) throws Exception{
		comConfig("COM1");
		while(true){
			Thread.sleep(1000);
			System.out.println(EWeightConstant.GOOD_WEIGHT);	
		}
		
	}
}

4.EWeightConstant.java

/**
 * 記錄串列埠的基礎資訊 全域性變數
 *
 */
public class EWeightConstant {
	/**
	 * 串列埠資料
	 */
	public static String GOOD_WEIGHT = "0";
	/**
	 * 串列埠是否開啟
	 */
	public static Boolean IS_OPEN_PORT = false;
}

5.Controller方法呼叫獲取串列埠資料,並作用於業務開發

/**
	 * 前端 呼叫該方法,用於獲取串列埠返回資料
	 * 如果想一直呼叫該串列埠返回資料,JS前端可做輪詢
	 * @param request
	 * @return
	 */
    @RequestMapping(value = "/getWeight", method = RequestMethod.GET)
    @ResponseBody
    public String getWeight(HttpServletRequest request) {
    	// 獲取資料的串列埠
    	final String E_WEIGHT_COM = "COM1";
    	try{
    		if(!EWeightConstant.IS_OPEN_PORT){
        		GetWeightUtil.comConfig(E_WEIGHT_COM);	
        	}
    	}catch(Exception e){
    		e.printStackTrace();
    	}
    	//全域性變數,記錄串列埠資料
    	String weight = EWeightConstant.GOOD_WEIGHT;
    	//輸出串列埠資料,檢視串列埠資料格式
    	System.out.println("獲取串列埠原始資料格式  = " + weight);
    	if(StringUtils.equals(weight, "0")){
    		return weight;
    	}
    	//擷取字串,獲取要取得資料部分
    	weight = weight.substring(weight.indexOf("+")+1, weight.indexOf("  "));
    	System.out.println("最終資料,返回擷取後的資料="+weight);
    	return weight;
    }