j2me提供了CommConnection對串口協議封裝,採用的是一種同步機制;一般的流程是:
發命令---》迴圈讀響應資料;這種操作很簡單,當互動的次數較多時,或者使用狀態機器時,代碼就是大迴圈套小迴圈,而且結構也不好看;所以,我想實現對串口封裝,實現一種非同步方式。對上層應用來說,要求如下:1. 啟動;啟動串口;2. 發送:發送命令;3. 如果有傳輸層協議,開啟定時器,當一定時間到達後未收到資料,認為異常;4. 當接收到資料後,回呼函數被調用,讀取資料;5. 關閉;關閉串口;在MIDP2.0中,MIDP的按鍵事件來源和底層作業系統以隊列為介面,MIDP從隊列中取出事件,處理後響應;最後回調Canvas的keyPressed;參照這種結構,我實現了串口的非同步方法呼叫:代碼如下所示:class CommHandler implements Runnable{<br />public synchronized void run(){<br />while(m_bDefaultCommHandler){<br />try{<br />int iLen = s_dis.available();<br />if(iLen > 0){<br />byte[] bData = new byte[iLen];<br />int iRet = s_dis.read(bData);<br />if(iRet > 0){<br />for(int i=0; i<iRet;i++){<br />if(s_commQueue.isFull()){<br />try{<br />wait();<br />}catch(InterruptedException ie){<br />ie.printStackTrace();<br />break;<br />}<br />}else{<br />s_commQueue.push(bData[i]);<br />}<br />}<br />}<br />}<br />}catch(IOException ioe){<br />ioe.printStackTrace();<br />break;<br />}<br />try{<br />wait();<br />}catch(InterruptedException ie){<br />ie.printStackTrace();<br />break;<br />}<br />}<br />}</p><p>public synchronized void proceed(){<br />try{<br />notify();<br />}catch(Throwable t){<br />t.printStackTrace();<br />}<br />}</p><p>public synchronized void send(byte[] bData) throws IOException{<br />s_dos.write(bData);<br />}<br />} CommHandler這個私人類的作用是:從串口取資料,壓入隊列中;CommHandler還提供了兩個方法:proceed方法用於控制線程繼續從串口取資料;send方法用於通過串口發送資料;CommDataQueue是一個私人類,實現迴圈隊列的功能;class CommDataQueue{<br />int m_iFront = 0;<br />int m_iRear = 0;<br />int QUEUE_LEN = 1000;<br />byte[] m_bQueue = new byte[QUEUE_LEN];</p><p>public synchronized void push(byte bData){<br />//if(isFull()){<br />//try{<br />//wait();<br />//}catch(InterruptedException ie){<br />//ie.printStackTrace();<br />//}<br />//}</p><p>m_iRear = (m_iRear+1)%QUEUE_LEN;<br />m_bQueue[m_iRear] = bData;<br />}</p><p>public synchronized byte get(){<br />if(isEmpty()){<br />return (byte)0xFF;<br />}</p><p>m_iFront = (m_iFront + 1)%QUEUE_LEN;<br />return m_bQueue[m_iFront];<br />}</p><p>public synchronized int available(){<br />return (m_iRear-m_iFront+QUEUE_LEN)%QUEUE_LEN;<br />}</p><p>public boolean isFull(){<br />return (m_iRear+1)%QUEUE_LEN == m_iFront;<br />}</p><p>public boolean isEmpty(){<br />return m_iRear == m_iFront;<br />}<br />} QueueEventHandler是一個私人類,它的作用是當隊列中有資料時,就回調;當隊列中沒有資料時,就觸發CommHandler從串口讀資料;m_cb是一個介面,定義如下:class QueueEventHandler implements Runnable{<br />public synchronized void run(){<br />while(m_bDefaultCommHandler){<br />if(s_commQueue.isEmpty()){<br />s_commHandler.proceed();<br />}else{<br />int iLen = s_commQueue.available();<br />byte[] bData = new byte[iLen];<br />for(int i=0; i<iLen; i++){<br />bData[i] = s_commQueue.get();<br />}<br />m_cb.dataComming(bData);<br />//s_commHandler.proceed();<br />}<br />}<br />}<br />} private DefaultCommHandlerCB m_cb;</p><p>public interface DefaultCommHandlerCB {<br />public void dataComming(byte[] bData);<br />}<br /> commHandler私人類、QueueEventHandler私人類、CommDataQueue私人類構成一個類DefaultCommHandler;在上層的使用方法如下所示:class closeT extends Thread{<br />public void run(){<br />DefaultCommHandler comm = DefaultCommHandler.getDefaultCommHandler();<br />try{<br />comm.close();<br />}catch(IOException ioe){<br />m_frm.append("close IOException:"+ioe.getMessage());<br />}<br />}<br />}</p><p>class sendT extends Thread{<br />public void run(){<br />DefaultCommHandler comm = DefaultCommHandler.getDefaultCommHandler();<br />try{<br />comm.send(m_tfSend.getString().getBytes());<br />}catch(IOException ioe){<br />m_frm.append("send IOException:"+ioe.getMessage());<br />}<br />}<br />}<br />class InQuery implements DefaultCommHandlerCB{<br />public void dataComming(byte[] bData){<br />m_tfRecv.setString(new String(bData,0,bData.length));<br />}<br />} 程式簡單地測試後,效果不錯。