国产强伦姧在线观看无码,中文字幕99久久亚洲精品,国产精品乱码在线观看,色桃花亚洲天堂视频久久,日韩精品无码观看视频免费

      您現(xiàn)在的位置:智能制造網(wǎng)>技術(shù)中心>串口驅(qū)動(dòng)分析

      直播推薦

      更多>

      企業(yè)動(dòng)態(tài)

      更多>

      推薦展會(huì)

      更多>

      串口驅(qū)動(dòng)分析

      2008年02月25日 09:14:47人氣:1005來源:浙江啟揚(yáng)智能科技有限公司

      雖然串口通訊已經(jīng)是普遍的標(biāo)準(zhǔn)而且廣為大家熟知,但驅(qū)動(dòng)中涉及的部分內(nèi)容也可能在平時(shí)的應(yīng)用中并不是很常用到,在這里做一個(gè)簡(jiǎn)單的介紹待后面說明到具體代碼的時(shí)候可以連貫一些。
      串行通訊接口是目*分流行的通訊接口之一。由于其電氣界面的簡(jiǎn)單性使其在計(jì)算機(jī)領(lǐng)域的應(yīng)用相當(dāng)?shù)膹V泛。在這里提到的串行通訊接口主要是指uart(通用串行)和irda兩種。通常的串行連接電氣連接上有3wire和9wire兩種。3wire的接線方式下定義了發(fā)送、接收和地三根連接。其用途就如名稱一樣分別用于發(fā)送、接收。下面是通常3wire連接的結(jié)構(gòu)框圖


      通常在串行接口控制器上會(huì)有兩個(gè)fifo用作接收和發(fā)送的緩沖,當(dāng)接收到數(shù)據(jù)后會(huì)直接將接收到的數(shù)據(jù)置入該緩沖器,并同時(shí)由控制電路向本地總線發(fā)出通知,以便讓本地總線將緩沖器內(nèi)的數(shù)據(jù)讀走,這樣在響應(yīng)(等待和讀取)的過程中仍然能通過緩沖器來接收數(shù)據(jù)。而發(fā)送發(fā)送的過程剛剛相反,本地總線可一直向發(fā)送緩沖寫入數(shù)據(jù)直到器填滿為止,而無需對(duì)每個(gè)數(shù)據(jù)的發(fā)送進(jìn)行等待。這就是基本的收發(fā)流程(這部分邏輯流程相信大家是zui熟悉的)。這一點(diǎn)在3wire和9wire中都是相同的。但是我們考慮下面的情況,如果接收一方的響應(yīng)由于某種原因的干擾(如處理器被其他中斷服務(wù)占用)的時(shí)候可能就來不及相應(yīng)之前receivefifo就可能被填滿了,這樣后續(xù)發(fā)送過來的數(shù)據(jù)就會(huì)丟失,這樣在需要數(shù)據(jù)可靠傳輸?shù)那闆r下串行通訊的弊端也就顯示出來了。如需要數(shù)據(jù)的可靠傳輸就需要對(duì)數(shù)據(jù)流的收發(fā)進(jìn)行控制。在9wire中將串行連接定義為如下形式。
      針號(hào)
      1
      2
      3
      4
      5
      6
      7
      8
      9
      縮寫
      dcd
      rxd
      txd
      dtr
      gnd
      dsr
      rts
      cts
      dell
      功能說明
      數(shù)據(jù)載波檢測(cè)
      接收數(shù)據(jù)
      發(fā)送數(shù)據(jù)
      數(shù)據(jù)終端就緒
      信號(hào)地
      數(shù)據(jù)設(shè)備就緒
      請(qǐng)求發(fā)送
      清除發(fā)送
      振鈴指示
      也就是說在原3wire的基礎(chǔ)上增加了dcd,dtr,dsr,rts,cts,dell六個(gè)控制線。其中rts/cts用于流控制,另外的dcd和dell則留作連接modem使用。有了專門的硬件流控制引腳也就使得流控制成為可能,以完成收發(fā)兩端的匹配使得數(shù)據(jù)可以可靠的傳輸。用rts/cts(請(qǐng)求發(fā)送/清除發(fā)送)流控制時(shí),應(yīng)將通訊兩端的rts、cts線對(duì)應(yīng)相連).在發(fā)送端準(zhǔn)備發(fā)送數(shù)據(jù)之前設(shè)置rts(request to send)也就使發(fā)送請(qǐng)求線,若接收端以作好接收準(zhǔn)備,就啟動(dòng)響應(yīng)的cts(clear to send)引線。這樣,收發(fā)雙發(fā)就進(jìn)入數(shù)據(jù)傳輸狀態(tài),在此過程中如若接收端處理數(shù)據(jù)的速度低于發(fā)送端的發(fā)送速度,接收一端還可以設(shè)置cts引線恢復(fù)原來阻塞得狀態(tài)以暫時(shí)中斷數(shù)據(jù)傳輸,之后若需要恢復(fù)數(shù)據(jù)傳輸恢復(fù)cts狀態(tài)即可。這樣uart的傳輸即實(shí)現(xiàn)了流控制,保障了數(shù)據(jù)傳輸?shù)耐陚湫浴?
      在這里還要說一下軟件流控制,雖然硬件已經(jīng)可以完成流控制的任務(wù)但很多少時(shí)候受到連線數(shù)的限制不能使用硬件流控制也就設(shè)計(jì)了專門的軟件流控制的方法。現(xiàn)在回到3線傳輸?shù)那榫?,若接收端接收?shù)據(jù)過程中緩沖器的負(fù)載到達(dá)某一限制(也就是留出一定的緩沖空間)時(shí)接收端向發(fā)送端發(fā)送一個(gè)特殊的標(biāo)示位(接收停止位),當(dāng)發(fā)送端收到該標(biāo)示的時(shí)候就停止發(fā)送,直到接收端緩沖器低于另一限制后發(fā)送標(biāo)示(接收許可位)給發(fā)送端,這樣就可以控制數(shù)據(jù)流的傳輸起停。這種軟件流控制是在給緩沖器留余量來完成的,在收發(fā)雙端處理器速度差很大的時(shí)候就不太適用了,就必須要用硬件流控制。

      其他幾個(gè)引腳都是與modem相關(guān)的,dsr數(shù)據(jù)裝置準(zhǔn)備好(data set ready)用于表明modem處于可以使用的狀態(tài)。dtr數(shù)據(jù)終端準(zhǔn)備好(data terminal ready)表明數(shù)據(jù)終端可以使用。這兩個(gè)信號(hào)用于檢查modem是否連接。dell腳當(dāng)有撥入時(shí)modem將會(huì)設(shè)置這個(gè)引腳。dcd信號(hào)是當(dāng)modem接收到數(shù)字載波信號(hào)的時(shí)候被設(shè)置,用于了解modem接收信號(hào)的情況。
      至于剩下的奇偶效驗(yàn)和停止位設(shè)置就只是需要針對(duì)寄存器設(shè)置無需軟件干涉就可以完成了。下面我們來看具體的驅(qū)動(dòng)程序。
       
      架構(gòu)
       在wince中串口的驅(qū)動(dòng)實(shí)現(xiàn)是有固定模型的,ce中的串口模型遵循iso/osi網(wǎng)絡(luò)通訊模型(7層),就是說串口屬于ce網(wǎng)絡(luò)模塊的一個(gè)部分。其中rs232界面(或其它的物理介質(zhì))實(shí)現(xiàn)網(wǎng)絡(luò)的物理層,而驅(qū)動(dòng)和serialapi共同組成數(shù)據(jù)鏈路層,其它部分都沒有做定義。在典型的應(yīng)用中,serialapi與間接通過tapi或直接與activesync交互,組成ce網(wǎng)絡(luò)的一部分。而紅外本身的協(xié)議就相對(duì)復(fù)雜的多,它有專門的一套模型來描述其使用規(guī)則,對(duì)紅外設(shè)備本身了解不多也就不能深入下去。在串口的這一側(cè),整個(gè)驅(qū)動(dòng)模型也是相當(dāng)?shù)膹?fù)雜的,但所幸的是驅(qū)動(dòng)僅僅使用到serialapi這一層,在這個(gè)層次上串口的行為還是相對(duì)簡(jiǎn)單的。
                     



















      我們這里僅僅涉及上面所提到的serial/irda driver這部分(綠色部分)。在wince提供的驅(qū)動(dòng)例程中串口/紅外驅(qū)動(dòng)采用分層結(jié)構(gòu)設(shè)計(jì),mdd提供框架性的實(shí)現(xiàn),負(fù)責(zé)提供os所需的基本實(shí)現(xiàn),并將代碼設(shè)計(jì)與具體的硬件設(shè)計(jì)無關(guān)。而pdd提供了對(duì)硬件操作相應(yīng)的代碼。這些代碼通過結(jié)構(gòu)hwobj來相互。對(duì)于mdd+pdd的整體驅(qū)動(dòng)來看,串口驅(qū)動(dòng)模型是作為stream來實(shí)現(xiàn)的。
      兩者合一以達(dá)到實(shí)現(xiàn)驅(qū)動(dòng)的目的。ddsi就是指這兩個(gè)部分之間的接口,這個(gè)接口并非受到強(qiáng)制的物理/邏輯關(guān)系來約束,而是人為的規(guī)定的。在涉及到一種特定硬件我們進(jìn)行針對(duì)實(shí)現(xiàn)的時(shí)候往往需要的是了解硬件的物理特性和控制邏輯,然后根據(jù)ddsi的約束就來進(jìn)行實(shí)現(xiàn)。對(duì)于這里描述的驅(qū)動(dòng)模型而言結(jié)合關(guān)鍵在于結(jié)構(gòu)指針hwobj的使用和具體實(shí)現(xiàn)。在實(shí)際的驅(qū)動(dòng)應(yīng)用中僅僅需要實(shí)現(xiàn)hwobj相關(guān)的一系列函數(shù),而無需從驅(qū)動(dòng)頂層*開發(fā)。串口驅(qū)動(dòng)模型作為一種常用驅(qū)動(dòng)模型在windowsce中常常用于串口/紅外/usb client的具體實(shí)現(xiàn)。該驅(qū)動(dòng)模型中對(duì)全功能的串口進(jìn)行了定義,除了常用的tx和rx引線定義以外,針對(duì)dtr、rts等功能引腳都進(jìn)行了支持,使得用該模型設(shè)計(jì)的串口驅(qū)動(dòng)支持流控制、具備驅(qū)動(dòng)modem等設(shè)備的能力。
      事實(shí)上,如果需要的話*可以將該驅(qū)動(dòng)一體化設(shè)計(jì)(拋開pdd-mdd的劃分,也就無須ddsi)。也就是不使用現(xiàn)有的驅(qū)動(dòng)架構(gòu)來進(jìn)行實(shí)現(xiàn)??紤]到串口驅(qū)動(dòng)的使用頻率和執(zhí)行效率要求都不是很苛刻的情況下拋棄驅(qū)動(dòng)架構(gòu)另外實(shí)現(xiàn)的就沒有多大必要了。
      對(duì)于驅(qū)動(dòng)本身而言,串行驅(qū)動(dòng)從功能和實(shí)現(xiàn)上相當(dāng)?shù)暮?jiǎn)單,確具被相當(dāng)全面的成分,對(duì)該驅(qū)動(dòng)的分析和了解無疑是學(xué)習(xí)流式驅(qū)動(dòng)程序很好的*。
      代碼分析
      在開始具體代碼之前我們先來看看,相關(guān)的一些結(jié)構(gòu)。 hwobj是相應(yīng)的硬件設(shè)備操作的抽象集合。結(jié)構(gòu)的定義后的注釋與實(shí)際的用途有點(diǎn)點(diǎn)出入,bandflagsist的啟動(dòng)時(shí)間,可選為在初始化過程啟動(dòng)或是在打開設(shè)備的時(shí)候起動(dòng)isr.而第二個(gè)參數(shù)則是攔截的具體的系統(tǒng)中斷號(hào)。zui后一個(gè)參數(shù)是一個(gè)結(jié)構(gòu),該結(jié)構(gòu)定義了硬件操作的各式行為函數(shù)的指針,mdd正是通過這些函數(shù)來訪問具體的pdd操作。
      typedef struct __hwobj {
          ulong         bindflags; // flags controlling mdd behaviour.  se above.
          dword    dwintid;   // interrupt identifier used if thread_at_init or thread_at_open
          phw_vtbl   pfunctbl;
      } hwobj, *phwobj;

      而hw_vtbl則是代表具體硬件操作函數(shù)指針的集合,該結(jié)構(gòu)所指向的函數(shù)包括了初始化、打開、關(guān)閉、接收、發(fā)送、設(shè)置baudrate等一系列操作。結(jié)構(gòu)存在就像紐帶一樣著pdd中的具體實(shí)現(xiàn)和mdd中的抽象操作。pdd的實(shí)現(xiàn)必須遵循h(huán)w_vtbl中所描述的函數(shù)形式,并構(gòu)造出相應(yīng)的hw_vtbl實(shí)例。驅(qū)動(dòng)的編寫就是針對(duì)這些函數(shù)來一一進(jìn)行實(shí)現(xiàn)。
      typedef struct __hw_vtbl    {
          pvoid           (*hwinit)(ulong identifier, pvoid pmddcontext, phwobj phwobj);
          bool            (*hwpostinit)(pvoid phead);
          ulong         (*hwdeinit)(pvoid phead);
          bool            (*hwopen)(pvoid phead);
          ulong         (*hwclose)(pvoid phead);
          interrupt_type (*hwgetintrtype)(pvoid phead);
          ulong         (*hwrxintrhandler)(pvoid phead, puchar ptarget, pulong pbytes);
          void             (*hwtxintrhandler)(pvoid phead, puchar psrc, pulong pbytes);
          void             (*hwmodemintrhandler)(pvoid phead);
          void             (*hwlineintrhandler)(pvoid phead);
          ulong         (*hwgetrxbuffersize)(pvoid phead);
          bool            (*hwpoweroff)(pvoid phead);
          bool            (*hwpoweron)(pvoid phead);
          void             (*hwcleardtr)(pvoid phead);
          void            (*hwsetdtr)(pvoid phead);
          void             (*hwclearrts)(pvoid phead);
          void             (*hwsetrts)(pvoid phead);
          bool            (*hwenableir)(pvoid phead, ulong baudrate);
          bool            (*hwdisableir)(pvoid phead);
          void             (*hwclearbreak)(pvoid phead);
          void             (*hwsetbreak)(pvoid phead);
          bool            (*hmitcomchar)(pvoid phead, uchar comchar);
          ulong         (*hwgetstatus)(pvoid phead, lpcomstat lpstat);
          void             (*hwreset)(pvoid phead);
          void             (*hwgetmodemstatus)(pvoid phead, pulong pmodemstatus);
          void             (*hwgetcommproperties)(pvoid phead, lpcommprop pcommprop);
          void             (*hwpurgecomm)(pvoid phead, dword fdwaction);
          bool            (*hwsetdcb)(pvoid phead, lpdcb pdcb);
          bool            (*hwsetcommtimeouts)(pvoid phead, lpcommtimeouts lpcommto);
          bool         (*hwioctl)(pvoid phead, dword dwcode,pbyte pbufin,dword dwlenin,
                             pbyte pbufout,dword dwlenout,pdword pdwactualout);
          } hw_vtbl, *phw_vtbl;交待了上述兩個(gè)結(jié)構(gòu)以后我們來看看具體的代碼,為保障對(duì)系統(tǒng)架構(gòu)的清晰認(rèn)識(shí),我們將mdd的代碼和pdd的代碼分開進(jìn)行分析。
       
      mdd部分
      由于串口驅(qū)動(dòng)由device.exe直接調(diào)用,所以mdd部分是以完整的stream接口給出的. 也就具備基于stream接口的驅(qū)動(dòng)程序所需的函數(shù)實(shí)現(xiàn),包括com_init,com_deinit
      ,com_open,com_close ,com_read ,com_write, com_seek,, com_powerup, com_powerdown, com_iocontrol幾個(gè)基本實(shí)現(xiàn)。由于串口發(fā)送/接收的信息并不能定位,而僅僅是簡(jiǎn)單的傳送,所以com_seek僅僅是形式上實(shí)現(xiàn)了一下。
      com_init
      com_init是該驅(qū)動(dòng)的初始化函數(shù),在設(shè)備管理器加載該驅(qū)動(dòng)后首先調(diào)用,用于初始化所需的變量,硬件設(shè)備等資源。該過程分配代表設(shè)備硬件實(shí)例的數(shù)據(jù)結(jié)構(gòu),并通過硬件抽象接口hwinit初始化硬件。同時(shí)該函數(shù)會(huì)調(diào)用interruptinitialize為接收內(nèi)核中的邏輯中斷創(chuàng)建相應(yīng)事件并初始化臨界區(qū)。該函數(shù)還需要得到硬件緩沖器的物理地址和獲知該緩沖器的大小(該沖器zui小為2k)。zui后它將建立相應(yīng)的緩沖作為接收的中介。下面我們來看這個(gè)函數(shù)的實(shí)現(xiàn)過程。
      在函數(shù)中定義了兩個(gè)重要的變量。pserialhead和phwhead.前者用于描述相應(yīng)的串口的狀態(tài),后者則是對(duì)應(yīng)硬件的數(shù)據(jù)抽象。首先為pserialhead分配空間和初始化鏈表和臨界區(qū)等數(shù)據(jù)并同時(shí)為接收和發(fā)送中斷創(chuàng)建事件。然后再從注冊(cè)表中獲得當(dāng)前的注冊(cè)項(xiàng)值(由于device.exe是根據(jù)注冊(cè)表鍵值來調(diào)用驅(qū)動(dòng)的,當(dāng)前鍵注冊(cè)表項(xiàng)指的就是與上述鍵值在同一根下的注冊(cè)項(xiàng))。得到devicearrayindex、priority256鍵下的具體值后就可以調(diào)用getserialob-ject(在pdd中實(shí)現(xiàn))來獲得具體的hwobj對(duì)象,并通過該對(duì)象來調(diào)用硬件初始化函數(shù)了。(由于在這里已經(jīng)對(duì)硬件進(jìn)行了初始化,之后的返回都需要調(diào)用com_deinit來完成。)由于硬件初始化(實(shí)際的驅(qū)動(dòng)初始化代碼)已經(jīng)得到執(zhí)行這個(gè)時(shí)候就只有分配和初始化緩沖的工作需要做了。所以調(diào)用hwgetrxbuffersize(pdd代碼)來獲取pdd中設(shè)定的緩沖大小,并根據(jù)返回的具體值分配緩沖。zui后如果bindflags被設(shè)定為thread_at_init就再調(diào)用startdispatchthread啟動(dòng)分發(fā)線程(實(shí)際的ist)。這樣就完成了系統(tǒng)初始化的操作。
      com_deinit
      當(dāng)驅(qū)動(dòng)被稱被卸下的時(shí)候該事件啟動(dòng),用作與com_init相反的操作。這個(gè)過程大致會(huì)釋放驅(qū)動(dòng)中所使用的資源,停止期間創(chuàng)建的線程等操作。具體說來,大致為停止在mdd中的所有ist,和釋放內(nèi)存資源和臨界區(qū)等系統(tǒng)資源。同時(shí)還需調(diào)用hwdeinit來釋放pdd中所使用到的系統(tǒng)資源。
      com_open
      com_oepn在cr-eatefile后被調(diào)用,用于以讀/寫模式打開設(shè)備,并初始化所需要的空間/資源等,創(chuàng)建相應(yīng)的實(shí)例,為后面的操作做好準(zhǔn)備。這里的代碼相對(duì)比較容易,下面就簡(jiǎn)單講一下。既然是初始化,肯定就免不了對(duì)參數(shù)的檢查。首先檢查通過com_init返回的phead結(jié)構(gòu)是否有效,這里雖然沒有顯式的在這兩個(gè)函數(shù)之間傳遞參數(shù),而是在設(shè)備管理器的內(nèi)部傳遞這個(gè)參數(shù)的。
      之后是檢查文件系統(tǒng)傳遞過來的open句柄中的open模式是否有效,這個(gè)參數(shù)由應(yīng)用程序產(chǎn)生,通過文件系統(tǒng)直接傳遞到驅(qū)動(dòng)。之后就開始初始化的操作,在這里將會(huì)建立相應(yīng)的hw_open_info實(shí)體。下面和為該結(jié)構(gòu)的定義。
      typedef struct __hw_open_info {
          phw_indep_info  pserialhead;    // @field pointer back to our hw_indep_info
          dword          accesscode;     // @field what permissions was this opened with
          dword          sharemode;      // @field what share mode was this opened with
          dword           structusers;    // @field count of threads currently using struct.
          comm_events       commevents;       // @field contains all in…. handling
          list_entry      llist;          // @field linked list of open_infos
          } hw_open_info, *ph
      結(jié)構(gòu)中的*個(gè)參數(shù)指向我們前面提到的hw_indep_info結(jié)構(gòu),第二個(gè)參數(shù)為操作權(quán)限碼,也就是read/write這類的權(quán)限。第三個(gè)參數(shù)為共享模式,以確定是否支持獨(dú)占。這兩個(gè)參數(shù)都是與文件系統(tǒng)的內(nèi)容對(duì)應(yīng)的。而commevent則對(duì)應(yīng)于本實(shí)例的事件。由于驅(qū)動(dòng)架構(gòu)支持多個(gè)open操作實(shí)例的存在,所以這里維護(hù)了一個(gè)鏈表來這些結(jié)構(gòu)。在這里由于ist的啟動(dòng)可以在com_init和com_open中進(jìn)行,還有處理器啟動(dòng)ist的內(nèi)容。準(zhǔn)備好hw_open_info結(jié)構(gòu)后就可以調(diào)用hwopen(pdd)來進(jìn)行pdd所需的open操作了。open操作完成后調(diào)用hwpurgecomm(pdd)來處理(取消或等待)當(dāng)前仍在通訊狀態(tài)的任務(wù)。然后重置軟件fifo就基本完成了com_open的動(dòng)作了。
      事實(shí)上這里主要是對(duì)所需的數(shù)據(jù)結(jié)構(gòu)進(jìn)行處理,對(duì)于硬件的具體操作都留給pdd去做了,mdd所維護(hù)的僅僅是一個(gè)架構(gòu)性的代碼。open操作完成后,驅(qū)動(dòng)就進(jìn)入了工作狀態(tài)這個(gè)時(shí)候。
      com_close
      com_close為與com_open相對(duì)應(yīng)的操作。這期間的目的是釋放com_open所使用的系統(tǒng)資源,除此以外如果在com_open期間創(chuàng)建了相應(yīng)的ist還需要停止該線程,在zui后將該hw_open_info脫鏈。這樣一來驅(qū)動(dòng)狀態(tài)就得以恢復(fù)。當(dāng)然這期間還做了一寫避免線程競(jìng)爭(zhēng)的處理,使得代碼看起來不是那么簡(jiǎn)單。
      startdispatchthread/stopdispatchthread
      這兩個(gè)函數(shù)都不是stream所需要的標(biāo)準(zhǔn)接口,但卻是中斷服務(wù)程序所需的ist啟動(dòng)和關(guān)閉的手段,所以在這里順便說一下。
      startdispatchthread函數(shù)用于啟動(dòng)ist,主要的工作為調(diào)用interruptinitialize將系統(tǒng)中斷與相應(yīng)的事件起來。并啟動(dòng)serialdispatchthread作為ist.其中調(diào)用了叫做 interruptdone的函數(shù),該函數(shù)會(huì)調(diào)用oal中的oeminterruptdone來完成中斷的響應(yīng)。
      stopdispatchthread用于與startdispatchthread相反的操作。停止的過程相對(duì)要復(fù)雜一些,該函數(shù)首先設(shè)定當(dāng)前線程的優(yōu)先級(jí)與分發(fā)線程相同,以便于在停止該線程的動(dòng)作不會(huì)比釋放內(nèi)存的動(dòng)作快以避免出錯(cuò)。停止的動(dòng)作是讓線程主動(dòng)完成的,具體的方法是提交表示位killrxthread然后通過sleep請(qǐng)求調(diào)度,待到ist自己停止。這個(gè)時(shí)候由于ist已經(jīng)停止所以在程序的zui后調(diào)用interruptdisable來屏蔽中斷。
      serialdispatchthread/ serialeventhandler
      serialdispatchthread/ serialeventhandler就是串口驅(qū)動(dòng)的中斷分發(fā)程序(也就是ist的所在)。整個(gè)ist被分開寫成兩個(gè)部分---循環(huán)主體和事件處理程序。循環(huán)主體serialdispatchthread內(nèi)容相對(duì)比較簡(jiǎn)單,反復(fù)等待串口事件并調(diào)用serialeventhandler對(duì)具體的中斷進(jìn)行處理,直到pserialhead->killrxthread被設(shè)置后退出。serialeventhandler為中斷處理的具體實(shí)現(xiàn),程序在獲得串口事件后運(yùn)行,目的在于對(duì)中斷進(jìn)行進(jìn)一步的判斷并執(zhí)行相應(yīng)的處理。
      下面參考兩個(gè)結(jié)構(gòu)體來完成接受和發(fā)送中斷服務(wù)的分析。我們先來看rx_buffer_info結(jié)構(gòu)。
      typedef struct __rx_buffer_info {
          ulong  read;             /* @field current read index. */
          ulong  write;            /* @field current write index. */
          ulong  length;              /* @field length of buffer */
          bool   dataavail;        /* @field bool reflecting existence of data. */
          puchar rxcharbuffer;     /* @field start of buffer */
          critical_section  cs;    /* @field critical section */
          } rx_buffer_info, *prx_buffer_info;
      用該結(jié)構(gòu)的原因是在驅(qū)動(dòng)內(nèi)部維護(hù)了一個(gè)緩沖器用作驅(qū)動(dòng)和應(yīng)用程序之間的緩沖見下圖.
      可以看到在硬件內(nèi)部已經(jīng)有一個(gè)fifo緩沖器,這保障了驅(qū)動(dòng)的數(shù)據(jù)接收,但由于應(yīng)用不一定能保障在驅(qū)動(dòng)獲得數(shù)據(jù)后及時(shí)將數(shù)據(jù)取走,因此在驅(qū)動(dòng)內(nèi)部維護(hù)了另外一個(gè)緩沖器。在rx_buffer_fifo結(jié)構(gòu)中的read成員為mdd取數(shù)據(jù)時(shí)在fifo的位置標(biāo)志,而pdd向軟件寫入數(shù)據(jù)的位標(biāo)則對(duì)應(yīng)被稱作write,dataavail用作表示緩沖器內(nèi)的數(shù)據(jù)是否有效。而rxcharbuffer則是指向軟件fifo的指針。當(dāng)收到數(shù)據(jù)的時(shí)候就將write標(biāo)示往上遞增,而程序向驅(qū)動(dòng)取數(shù)得時(shí)候read遞增,這樣就可以根據(jù)read和write成員來維護(hù)這個(gè)fifo。有了這個(gè)基本思路墊底我們接著看rx的中斷服務(wù)具體如何實(shí)現(xiàn)。這間還會(huì)涉及到流控制的成分。
      接收分支:在接收分支的開始計(jì)算軟件緩沖器的剩余空間,如果有剩余的空間的話直接調(diào)用hwrxintrhandler(pdda實(shí)現(xiàn))來從硬件緩沖區(qū)獲取剩余空間大小的數(shù)據(jù),若已無剩余空間則建立一個(gè)16byte的臨時(shí)緩沖區(qū),將數(shù)據(jù)讀入該區(qū)域,實(shí)際上這個(gè)緩沖區(qū)在后面根本就不會(huì)被讀取所以這些數(shù)據(jù)全部丟失掉了這也就自然需要統(tǒng)計(jì)硬件/軟件緩沖導(dǎo)致的數(shù)據(jù)丟失(接收不及時(shí)導(dǎo)致)。接下來就是所謂xflow的流程了,所謂xflow就是我們上面提到的軟件流控制。也就是用軟件的方法來協(xié)調(diào)發(fā)送和接收端的收發(fā),保障數(shù)據(jù)的完整接收。當(dāng)接收到xoff/xon標(biāo)記的時(shí)候由于這個(gè)標(biāo)記本身不數(shù)據(jù)數(shù)據(jù)而是控制標(biāo)志,所以要講后面的數(shù)據(jù)全部前置一位,覆蓋掉xon/xoff的位置。同時(shí)還需要根據(jù)標(biāo)示的具體狀態(tài)來設(shè)置dcb結(jié)構(gòu)中的控制標(biāo)示來控制數(shù)據(jù)收發(fā)流程。如果是xon標(biāo)志,還需要在處理完接收流程后恢復(fù)發(fā)送流程。接收的動(dòng)作會(huì)改變write標(biāo)記的位置,這里需要重新計(jì)算該標(biāo)示。至于硬件流控制的流程中該驅(qū)動(dòng)模型是以緩沖器的75%為分位點(diǎn)來起停收發(fā)的,可用的硬件連線可以是dtr,也可以是rts(模式相同僅僅是連線不同),這里的操作很簡(jiǎn)單,僅僅是通過計(jì)算緩沖器的存儲(chǔ)狀態(tài)來清除該標(biāo)志就完成了硬件流控制的操作。由于在此過程中ist與其他部分是同步執(zhí)行的,所以這個(gè)時(shí)候如果使用xflow可能還會(huì)需要做一次安全檢查。這樣接收的流程就結(jié)束了。
      發(fā)送分支: 我們同樣來看看tx_buffer_info結(jié)構(gòu),看樣子似乎該結(jié)構(gòu)維護(hù)了一個(gè)和tx緩沖類似的緩沖區(qū),但事實(shí)上這個(gè)緩沖區(qū)域是不獨(dú)立存在的,發(fā)送的流程因?yàn)榭梢灾苯邮褂盟璋l(fā)送的數(shù)據(jù)的存儲(chǔ)區(qū)域來作為發(fā)送緩沖,所以這個(gè)緩沖沒有獨(dú)立存在的必要。由于使用其它進(jìn)程的數(shù)據(jù)區(qū)域,所以這里增加了權(quán)限控制項(xiàng)的成分,用于突破進(jìn)程間的訪問限制。
      typedef struct __tx_buffer_info {
          dword  permissions;      /* @field current permissions */
          ulong  read;             /* @field current read index. */
          ulong  length;              /* @field length of buffer */
          puchar txcharbuffer;     /* @field start of buffer */
          critical_section  cs;    /* @field critical section */
      } tx_buffer_info, *ptx_buffer_info;
      下面來看看代碼的具體內(nèi)容。首先是對(duì)opencnt的檢查,也就是設(shè)備是否被打開。若當(dāng)會(huì)話已經(jīng)關(guān)閉也就沒有必要繼續(xù)將數(shù)據(jù)送出了,并同時(shí)重置緩沖器的各個(gè)標(biāo)志位。整個(gè)流程比較簡(jiǎn)單,在需要流控制時(shí)設(shè)置rts或檢查xflow的情況后將數(shù)據(jù)送入硬件緩沖器.如果在沒有數(shù)據(jù)需要發(fā)送的情況下簡(jiǎn)單的清除中斷標(biāo)示并發(fā)出發(fā)送結(jié)束事件就可以了。至于setprocpermissions設(shè)置的目的在于獲得訪問其它線程數(shù)據(jù)空間的手段。
      至于所謂的modem和line的情況則全部交給pdd來處理,我們后面再討論。在這些全部都處理完了以后如果前面處理了接收,則發(fā)出接收(有可用的數(shù)據(jù)用于接收)的消息,讓程序開始接收。后面還跟進(jìn)了一個(gè)evaluateeventflag 函數(shù),這個(gè)函數(shù)用于產(chǎn)生標(biāo)準(zhǔn)的communication events ev_rxflag,而且由于該驅(qū)動(dòng)程序本身支持mult-open模式,所以需要將該事件送發(fā)到所有的實(shí)例中去。在ist期間有一些互鎖、臨界區(qū)的操作,因?yàn)椴挥绊懥鞒蹋交膬?nèi)容這里我沒有提。中斷服務(wù)的分析大致就是如此,沒有涉及到邏輯環(huán)節(jié)在后面的pdd部分再進(jìn)行討論。
          
      com_read
      com_read是獲取串口所接收到數(shù)據(jù)的操作,在前面的ist中沒有看到對(duì)rx buffer進(jìn)行修改read標(biāo)記的操作,也就是這兒來完成的。該函數(shù)有三個(gè)參數(shù),*個(gè)參數(shù)是從上面的com_open通過設(shè)備管理器交換來的,后兩個(gè)參數(shù)與文件系統(tǒng)的使用方法*一樣,一個(gè)是接受緩沖指針,另一個(gè)是長(zhǎng)度。代碼的開始照樣是例行公事的參數(shù)檢查,包括對(duì)存取權(quán)限,opencnt等。之后計(jì)算超時(shí)時(shí)間,如果設(shè)定了超時(shí)讀取動(dòng)作會(huì)在超時(shí)后返回,不管是否讀到了足夠長(zhǎng)度的數(shù)據(jù)。隨后就是簡(jiǎn)單對(duì)軟件緩沖進(jìn)行讀取的操作了,讀取的操作是在rx_cs中完成的。下面要處理器的主要就是幾種異常的情形,讀取過程中設(shè)備被關(guān)閉/取消讀取和超時(shí)。zui后在讀取的過程中需要處理的就只是流控制的成本了。首先是軟件流的情形,如果緩沖的狀態(tài)由高于分位點(diǎn)至分位點(diǎn)以下就發(fā)出xon標(biāo)記,啟動(dòng)發(fā)送端的發(fā)送。而硬件流的情形無論是rts還是dtr與軟件流的相類似,同樣由一個(gè)分為點(diǎn)(50%)來決定發(fā)出啟動(dòng)發(fā)送端的信號(hào),僅僅是這里使用的具體措施的不同。這些硬件信號(hào)的發(fā)出都是由pdd來完成的,其中包括hwsetrts和hwsetdtr(2選一)。至此read的流程就結(jié)束了。
      com_write
      com_write是與com_read相對(duì)應(yīng)的操作。所傳遞的參數(shù)的形式也是很相似的,僅僅是數(shù)據(jù)流向的不同。在程序的開始,同樣也是參數(shù)檢查,內(nèi)容與com_read一致。在數(shù)據(jù)檢查完成之后進(jìn)入臨界區(qū)(保障多線程下的獨(dú)占)將送入的目標(biāo)地址和長(zhǎng)度設(shè)置為tx buffer,待到數(shù)據(jù)發(fā)送完成事件后調(diào)用dotxdata來啟動(dòng)發(fā)送。這里啟動(dòng)發(fā)送的目的在于獲得硬件中斷維持發(fā)送流程。在這里dotxdata是作為兩種狀態(tài)來執(zhí)行的,在通過com_write的執(zhí)行的過程中是在device.exe所創(chuàng)建的線程空間內(nèi)執(zhí)行的,但由系統(tǒng)中斷事件主動(dòng)啟動(dòng)的過程中屬于ist本身的的進(jìn)程空間,這樣在com_write中調(diào)用dotxdata之前設(shè)置的權(quán)限代碼(由getcurrentpermissions獲得)就可以由txbufferinfo傳遞到ist中去使得中斷過程也具備了訪問緩沖的權(quán)限(結(jié)合前面說明ist的流程)。當(dāng)提交中斷處理發(fā)送后待到pserialhead->htransmitevent被設(shè)置或是異?;虺瑫r(shí)后就結(jié)束了發(fā)送流程,在這部分的zui后。與com_read類似需要處理一些異常情況,當(dāng)然如果使用了硬件流控制還需要在這里清除掉發(fā)送請(qǐng)求信號(hào),當(dāng)這些狀態(tài)處理完成以后發(fā)送ev_txempty事件通告所有open的句柄發(fā)送結(jié)束就完成了該部分的流程。
      com_powerup/ com_powerdown
      這兩個(gè)函數(shù)的調(diào)用都由ce的電源事件來引發(fā),mdd并沒有對(duì)這兩個(gè)函數(shù)進(jìn)行處理,僅僅是將其傳遞給pdd。
      com_iocontrol
      該函數(shù)用于實(shí)現(xiàn)向設(shè)備發(fā)送命令的功能。由于代碼本身沒有什么流程或邏輯性可言,全都是單獨(dú)的實(shí)現(xiàn),下面就用列表的方式大致的說一下這些命令字和其實(shí)現(xiàn)。
      command
      note
      ioctl_psl_notify
      在調(diào)用驅(qū)動(dòng)的進(jìn)程退出時(shí)產(chǎn)生,并不是串行驅(qū)動(dòng)專有的io命令。這里會(huì)調(diào)用 processexiting函數(shù)進(jìn)行處理。這個(gè)函數(shù)的內(nèi)容放到后面來看。
      ioctl_serial_set_break_on
      中斷(暫停)serial當(dāng)前的發(fā)送或是接收,具體實(shí)現(xiàn)在pdd中
      ioctl_serial_set_break_off
      從中斷(暫停)狀態(tài)恢復(fù),具體實(shí)現(xiàn)在pdd中
      ioctl_serial_set_dtr
      將dtr引線拉高。(直接調(diào)用pdd實(shí)現(xiàn))
      ioctl_serial_clr_dtr
      將dtr引線拉低。(直接調(diào)用pdd實(shí)現(xiàn))
      ioctl_serial_set_rts
      將rts引線拉高。(直接調(diào)用pdd實(shí)現(xiàn))
      ioctl_serial_clr_rts
      將rts引線拉低。(直接調(diào)用pdd實(shí)現(xiàn))
      ioctl_serial_set_xoff
      軟件流模式下中止數(shù)據(jù)發(fā)送(xflow控制)
      ioctl_serial_set_xon
      軟件流模式下啟動(dòng)數(shù)據(jù)發(fā)送(xflow控制)
      ioctl_serial_get_wait_mask
      獲取當(dāng)前的事件對(duì)象
      ioctl_serial_set_wait_mask
      設(shè)置事件對(duì)象,這個(gè)過程相對(duì)比較麻煩,要將當(dāng)前獲得的事件對(duì)象mask設(shè)置到所有的open實(shí)例中,這和前面的 evaluateeventflag過程相似。
      ioctl_serial_wait_on_mask
      等待與提供的事件相同的事件發(fā)生,實(shí)現(xiàn)實(shí)體是 waitcommevent后面再討論。
      ioctl_serial_get_commstatus
      清除異常并返回當(dāng)前狀態(tài)(由pdd實(shí)現(xiàn))
      ioctl_serial_get_modemstatus
      獲取modem狀態(tài)(由pdd實(shí)現(xiàn))
      ioctl_serial_get_properties
      獲取通訊************************(由pdd實(shí)現(xiàn))
      ioctl_serial_set_timeouts
      設(shè)置超時(shí)時(shí)間(包含pdd實(shí)現(xiàn))
      ioctl_serial_get_timeouts
      獲取超時(shí)時(shí)間
      ioctl_serial_purge
      清除制定的發(fā)送或接收緩沖內(nèi)的數(shù)據(jù)(含pdd實(shí)現(xiàn))
      ioctl_serial_set_queue_size
      不明,若知道請(qǐng)告知
      ioctl_serial_immediate_char
      為擴(kuò)展功能,在發(fā)送數(shù)據(jù)前設(shè)置一個(gè)標(biāo)志數(shù)
      ioctl_serial_get_dcb
      獲取dcb數(shù)據(jù)結(jié)構(gòu)
      ioctl_serial_set_dcb
      設(shè)置dcb數(shù)據(jù)結(jié)構(gòu)
      ioctl_serial_enable_ir
      啟動(dòng)紅外模式(由pdd實(shí)現(xiàn))
      ioctl_serial_disable_ir
      禁用紅外模式(由pdd實(shí)現(xiàn))
      到這里mdd的主要函數(shù)都已經(jīng)介紹過了,下面幾個(gè)函數(shù)是在deviceiocontrol中用到的。這里順便也來看一下:
      processexiting
      該函數(shù)在ioctl_psl_notify命令的執(zhí)行過程中被調(diào)用,之前的情景是使用驅(qū)動(dòng)的進(jìn)程在被取消的過程中,在這里主要是清除所有正在會(huì)話中的線程。以便直接kill掉該進(jìn)程。
      waitcommevent
      事實(shí)上該函數(shù)為serialapi waitcommevent在驅(qū)動(dòng)內(nèi)的實(shí)現(xiàn),其作用為阻塞線程直道某一固定的串口通告(事件消息)發(fā)生。在具體的實(shí)現(xiàn)中,是用waitforsingleob-ject來實(shí)現(xiàn)阻塞。在進(jìn)入阻塞之前,函數(shù)適用一個(gè)循環(huán)主體首先查詢是否存在已有的通告與等待通告相符,若沒有就等待下一次事件發(fā)生,待事件發(fā)生再次進(jìn)行檢查。如此循環(huán)達(dá)到阻塞的目的。
      applydcb
      dcb數(shù)據(jù)結(jié)構(gòu)是描述串行口波特率,流控制,奇偶效驗(yàn)等資料的載體。該函數(shù)是mdd設(shè)置dcb數(shù)據(jù)結(jié)構(gòu)至驅(qū)動(dòng)內(nèi)部和硬件的手段,這里使用了大量的pdd操作來完成硬件設(shè)置。
      總結(jié):
      在驅(qū)動(dòng)實(shí)現(xiàn)方面,除去所謂multi-open的處理外,串口的mdd并沒有什么特別的之處,在掌握了硬件行為和應(yīng)用軟件行為后很容易能讀懂其間的代碼。
      全年征稿/資訊合作 聯(lián)系郵箱:1271141964@qq.com

      免責(zé)聲明

      • 凡本網(wǎng)注明"來源:智能制造網(wǎng)"的所有作品,版權(quán)均屬于智能制造網(wǎng),轉(zhuǎn)載請(qǐng)必須注明智能制造網(wǎng),http://towegas.com。違反者本網(wǎng)將追究相關(guān)法律責(zé)任。
      • 企業(yè)發(fā)布的公司新聞、技術(shù)文章、資料下載等內(nèi)容,如涉及侵權(quán)、違規(guī)遭投訴的,一律由發(fā)布企業(yè)自行承擔(dān)責(zé)任,本網(wǎng)有權(quán)刪除內(nèi)容并追溯責(zé)任。
      • 本網(wǎng)轉(zhuǎn)載并注明自其它來源的作品,目的在于傳遞更多信息,并不代表本網(wǎng)贊同其觀點(diǎn)或證實(shí)其內(nèi)容的真實(shí)性,不承擔(dān)此類作品侵權(quán)行為的直接責(zé)任及連帶責(zé)任。其他媒體、網(wǎng)站或個(gè)人從本網(wǎng)轉(zhuǎn)載時(shí),必須保留本網(wǎng)注明的作品來源,并自負(fù)版權(quán)等法律責(zé)任。
      • 如涉及作品內(nèi)容、版權(quán)等問題,請(qǐng)?jiān)谧髌钒l(fā)表之日起一周內(nèi)與本網(wǎng)聯(lián)系,否則視為放棄相關(guān)權(quán)利。

      <
      更多 >

      工控網(wǎng)機(jī)器人儀器儀表物聯(lián)網(wǎng)3D打印工業(yè)軟件金屬加工機(jī)械包裝機(jī)械印刷機(jī)械農(nóng)業(yè)機(jī)械食品加工設(shè)備制藥設(shè)備倉儲(chǔ)物流環(huán)保設(shè)備造紙機(jī)械工程機(jī)械紡織機(jī)械化工設(shè)備電子加工設(shè)備水泥設(shè)備海洋水利裝備礦冶設(shè)備新能源設(shè)備服裝機(jī)械印染機(jī)械制鞋機(jī)械玻璃機(jī)械陶瓷設(shè)備橡塑設(shè)備船舶設(shè)備電子元器件電氣設(shè)備


      我要投稿
      • 投稿請(qǐng)發(fā)送郵件至:(郵件標(biāo)題請(qǐng)備注“投稿”)1271141964.qq.com
      • 聯(lián)系電話0571-89719789
      工業(yè)4.0時(shí)代智能制造領(lǐng)域“互聯(lián)網(wǎng)+”服務(wù)平臺(tái)
      智能制造網(wǎng)APP

      功能豐富 實(shí)時(shí)交流

      智能制造網(wǎng)小程序

      訂閱獲取更多服務(wù)

      微信公眾號(hào)

      關(guān)注我們

      抖音

      智能制造網(wǎng)

      抖音號(hào):gkzhan

      打開抖音 搜索頁掃一掃

      視頻號(hào)

      智能制造網(wǎng)

      公眾號(hào):智能制造網(wǎng)

      打開微信掃碼關(guān)注視頻號(hào)

      快手

      智能制造網(wǎng)

      快手ID:gkzhan2006

      打開快手 掃一掃關(guān)注
      意見反饋
      關(guān)閉
      企業(yè)未開通此功能
      詳詢客服 : 0571-87858618