本文導(dǎo)讀
在使用AWBus-lite對設(shè)備進(jìn)行管理時,無論設(shè)備處于 AWBus-lite拓?fù)浣Y(jié)構(gòu)中的哪個位置,只要其能夠提供某種標(biāo)準(zhǔn)服務(wù),就可以使用相應(yīng)的通用接口對其進(jìn)行操作。本文將從接口的定義和實(shí)現(xiàn)兩個方面,深入理解AWbus-lite工作的原理。
本文為《面向AWorks框架和接口的編程》第三部分軟件篇——第13章——第1~2小節(jié):通用接口的定義和接口的實(shí)現(xiàn)。本章導(dǎo)讀
在基于AWBus-lite總線拓?fù)浣Y(jié)構(gòu)的設(shè)備管理框架中,無論一個設(shè)備處于AWBus-lite總線拓?fù)浣Y(jié)構(gòu)中的哪個位置,只要其能夠提供某種標(biāo)準(zhǔn)服務(wù),就可以使用相應(yīng)的通用接口對其進(jìn)行訪問。那么,這究竟是怎樣實(shí)現(xiàn)的呢?本章將繼續(xù)深入探討AWBus-lite,為您揭開AWBus-lite的神秘面紗,使您對AWBus-lite有更加深入的了解,在具有這些足夠的了解后,你將有能力獨(dú)立開發(fā)一些設(shè)備的驅(qū)動,當(dāng)后續(xù)遇到一些AWorks暫不支持的設(shè)備時,可以自行開發(fā)設(shè)備相應(yīng)的驅(qū)動。
13.1 通用接口的定義
合理的接口應(yīng)該是簡潔的、易閱讀的、職責(zé)明確的,為了便于維護(hù),通用接口由廣州致遠(yuǎn)電子有限公司進(jìn)行統(tǒng)一的定義,用戶通常不需要自行定義通用接口。目前,常用的功能都已經(jīng)被標(biāo)準(zhǔn)化,定義了相應(yīng)的通用接口。
作為一種了解,下面以LED為例,從接口的命名、參數(shù)和返回值三個方面闡述在AWorks中定義接口的一般方法。
13.1.1 接口命名
在AWorks中,所有通用接口均以“aw_”開頭,緊接著是操作對象的名字,對于LED控制接口來說,所有接口都應(yīng)該以“aw_led_”作為前綴。
在接口的前綴定義好之后,應(yīng)該考慮需要定義哪些功能性接口,然后根據(jù)功能完善接口名。對于LED來說,核心的操作是控制LED的狀態(tài),點(diǎn)亮或熄滅LED,為此,可以定義一個設(shè)置(set)LED狀態(tài)的函數(shù),比如:“aw_led_set”。
使用該接口可以設(shè)置LED的狀態(tài),顯然,為了區(qū)分是點(diǎn)亮還是熄滅LED,需要通過一個額外的參數(shù)來指定具體的操作。
每次開燈或關(guān)燈都需要傳遞額外的參數(shù)給aw_led_set()接口,顯得比較繁瑣。為了簡化操作,可以為常用的開燈和關(guān)燈操作定義專用的接口,這樣就不需要額外的參數(shù)來對開燈和關(guān)燈操作進(jìn)行具體的區(qū)分了。比如,使用on和off分別表示開燈和關(guān)燈,則可以定義開燈的接口名為:“aw_led_on”,關(guān)燈的接口名為:
“aw_led_off”。
在一些特殊的應(yīng)用場合中,比如,LED閃爍,用戶可能并不關(guān)心具體的操作是開燈還是關(guān)燈,它僅僅需要LED的狀態(tài)發(fā)生翻轉(zhuǎn)。此時,可以定義一個用于翻轉(zhuǎn)(toggle)LED狀態(tài)的專用接口,比如:“aw_led_toggle”
13.1.2 接口參數(shù)
在AWorks中,通用接口的第一個參數(shù)往往用于表示要操作的具體對象。顯然,在一個系統(tǒng)中,可能存在多個LED,為了區(qū)分各個LED,可以為每個LED分配一個唯一編號,即ID號。ID號是一個從0開始的整數(shù),例如,系統(tǒng)中有兩個LED,則編號分別為0、1?;诖?,為了指定要操作的具體LED,通用接口的第一個參數(shù)可以設(shè)定為int類型的id。
對于aw_led_set接口,其除了使用id確定需要控制的LED外,還需要使用一個參數(shù)來區(qū)分是點(diǎn)亮LED還是熄滅LED,這是一個二選一的操作,對應(yīng)參數(shù)的類型可以使用布爾類型: aw_bool_t。當(dāng)值為真(AW_TRUE)時,則點(diǎn)亮LED;當(dāng)值為假(AW_FALSE)時,則熄滅LED?;诖?,可以定義aw_led_set()接口的原型為(還未定義返回值):
對于aw_led_on、aw_led_off和aw_led_toggle接口來說,它們的職責(zé)單一,僅僅需要指定控制的LED,即可完成點(diǎn)亮、熄滅或翻轉(zhuǎn)操作,無需其它額外的參數(shù)。對于這類接口,參數(shù)僅僅需要id,這些接口的原型可以定義如下(還未定義返回值):
13.1.3 返回值
對于用戶來說,調(diào)用通用接口后,應(yīng)該可以獲取到本次執(zhí)行的結(jié)果,是執(zhí)行成功還是執(zhí)行失敗,或是一些其它的有用信息。比如,在調(diào)用接口時,如果指定的id超過了有效范圍,由于沒有與無效id對應(yīng)的LED設(shè)備,操作必定會失敗,此時必須返回通過返回值告知用戶操作失敗,且操作失敗的原因是id不在有效范圍內(nèi),無與之對應(yīng)的LED設(shè)備。
在AWorks中,接口通常返回一個aw_err_t類型的返回值來表示接口執(zhí)行的結(jié)果,返回值的含義已被標(biāo)準(zhǔn)化:若返回值為AW_OK,則表示操作成功;若返回值為負(fù)數(shù),則表示操作失敗,此時,用戶可根據(jù)具體的返回值,查找aw_errno.h文件中定義的宏,根據(jù)宏的含義確定失敗的原因;若返回值為正數(shù),其含義與具體接口相關(guān),由具體接口定義,無特殊說明則表示不會返回正數(shù)。AW_OK是在aw_common.h文件中定義的宏,其定義如下:
錯誤號在aw_errno.h文件中定義,幾個常見錯誤號的定義詳見表6.2。比如,在調(diào)用LED通用接口時,若id不在有效范圍內(nèi),則該id沒有對應(yīng)的LED設(shè)備,此時接口應(yīng)該返回-AW_ENODEV。注意:AW_ENODEV的前面有一個負(fù)號,以表示負(fù)值。
基于此,將所有LED通用接口的返回值類型定義為aw_err_t,LED控制接口的完整定義詳見表13.1,其對應(yīng)的類圖詳見圖13.1。
表13.1 LED通用接口(aw_led.h)
圖13.1 LED接口類圖
這些接口都已經(jīng)在aw_led.h文件中完成了定義,無需用戶再自行定義。上述從接口命名、參數(shù)和返回值三個方面詳細(xì)闡述了一套接口定義的方法,旨在讓用戶了解接口的由來,加深對接口的理解。實(shí)際中,定義接口并不是一件容易的事情,需要盡可能考慮到所有的情況,接口作為與用戶交互的途徑,一旦定義完成,如非必要,都應(yīng)該避免再對接口進(jìn)行修改。否則,所有依賴于該接口的應(yīng)用程序都將受到影響。因此,當(dāng)前并不建議用戶自定義通用接口,通用接口的定義應(yīng)由廣州致遠(yuǎn)電子有限公司統(tǒng)一規(guī)劃、定義、維護(hù)和管理。
13.2 接口的實(shí)現(xiàn)
作為一種范例,下面以實(shí)現(xiàn)LED接口為例,詳細(xì)介紹AWorks中實(shí)現(xiàn)接口的一般方法。
13.2.1 實(shí)現(xiàn)接口初探
在AWorks中,硬件設(shè)備和驅(qū)動統(tǒng)一由AWBus-lite進(jìn)行管理,因此,對于LED這一類硬件設(shè)備,其實(shí)現(xiàn)是屬于AWBus-lite的一部分。LED有4個通用接口函數(shù),其中的aw_led_on()和aw_led_off()接口可以直接基于aw_led_set()接口實(shí)現(xiàn),詳見程序清單13.1。
程序清單13.1 aw_led_on()和aw_led_off()接口的實(shí)現(xiàn)
實(shí)現(xiàn)接口的核心是實(shí)現(xiàn)aw_led_set()和
aw_led_toggle()這兩個接口。對于不同的底層硬件設(shè)備,LED實(shí)際控制方式是不同的,比如,最常見的,通過GPIO直接控制一個LED,簡單范例詳見程序清單13.2。
程序清單13.2 aw_led_set()的實(shí)現(xiàn)(GPIO控制LED)
也有可能是通過串口控制一個LED設(shè)備。例如,通過發(fā)送字符串命令控制LED的狀態(tài),命令格式為:set
程序清單13.3 aw_led_set()的實(shí)現(xiàn)(UART控制LED)
總之,底層硬件設(shè)備是多種多樣的,不同類型的LED設(shè)備對應(yīng)的控制方式也會不同。
定義通用接口的目的在于屏蔽底層硬件的差異性,即無論底層硬件如何變化,用戶都可以使用通用接口控制LED。顯然,如果直接類似程序清單13.2和程序清單13.3這樣實(shí)現(xiàn)一個通用接口,那么隨著LED設(shè)備種類的增加,同一個接口的實(shí)現(xiàn)代碼將有越來越多不同的版本。
在一個應(yīng)用程序中,一個接口不能同時具有多種不同的實(shí)現(xiàn),因此,這樣的做法有著非常明顯的缺點(diǎn):多個不同種類的LED設(shè)備不能在一個應(yīng)用中共存,更換硬件設(shè)備,就必須更換通用接口的實(shí)現(xiàn),使用何種設(shè)備就加入相應(yīng)設(shè)備的控制代碼進(jìn)行編譯。 例如,系統(tǒng)中有幾個直接通過GPIO控制的LED,同時也存在幾個通過UART控制的LED,那么,類似程序清單13.2和程序清單13.3這樣直接實(shí)現(xiàn)通用接口的方法,就無法組織代碼了,因?yàn)椴豢赡芡瑫r將程序清單13.2和程序清單13.3所示的代碼加入工程編譯。顯然,需要更好的辦法來解決這個問題。
13.2.2 LED抽象方法
在使用幾種控制方式不同的LED硬件設(shè)備時,雖然它們對應(yīng)的aw_led_set()和aw_led_toggle()接口的具體實(shí)現(xiàn)方法并不相同,但它們要實(shí)現(xiàn)的功能卻是一樣的,這是它們的共性:均要實(shí)現(xiàn)設(shè)置LED狀態(tài)和翻轉(zhuǎn)LED狀態(tài)的功能。由于一個接口的實(shí)現(xiàn)代碼只能有一份,因此,這些功能的實(shí)現(xiàn)不能直接作為通用接口的實(shí)現(xiàn)代碼。為此,可以在通用接口和具體實(shí)現(xiàn)之間增加一個抽象層,以對共性進(jìn)行抽象,將兩種功能的實(shí)現(xiàn)抽象為如下兩個方法:
相對于通用接口來說,抽象方法多了一個p_cookie參數(shù)。在面向?qū)ο蟮木幊陶Z言中(如C++),對象中的方法都能通過隱式指針p_this訪問對象自身,引用自身的一些私有數(shù)據(jù)。而在C語言中則需要顯式的聲明,這里的p_cookie就有類似的作用,當(dāng)前設(shè)置為void *類型主要是由于具體對象的類型還并不確定。
為了節(jié)省內(nèi)存空間,同時方便管理,可以將所有抽象方法放在一個結(jié)構(gòu)體中,形成一張?zhí)摵瘮?shù)表,比如:
由于LED的實(shí)現(xiàn)屬于AWBus-lite的一部分,因此,命名使用"awbl_"作為前綴。這里定義了一個虛函數(shù)表,包含了兩個方法,分別用于設(shè)置LED的狀態(tài)和翻轉(zhuǎn)LED。針對不同的硬件設(shè)備,都可以根據(jù)自身特性實(shí)現(xiàn)這兩個方法。GPIO控制LED的偽代碼詳見程序清單13.4,UART控制LED的偽代碼詳見程序清單13.5。
程序清單13.4 抽象方法的實(shí)現(xiàn)(GPIO控制LED)
程序清單13.5 抽象方法的實(shí)現(xiàn)(UART控制LED)
顯然,__g_led_gpio_drv_funcs和
__g_led_uart_drv_funcs分別是使用GPIO和UART控制LED的具體實(shí)現(xiàn),它們在形式上是兩個不同的結(jié)構(gòu)體常量,在同一系統(tǒng)中是可以共存的。
13.2.3 抽象的LED服務(wù)
當(dāng)對不同的LED硬件設(shè)備抽象了相同的
pfn_led_set和pfn_led_toggle方法后,在通用接口aw_led_set()和aw_led_toggle()的實(shí)現(xiàn)中,就無需再處理與硬件相關(guān)的具體事務(wù),只需要找到相應(yīng)設(shè)備提供的相應(yīng)方法,然后調(diào)用這些具體硬件設(shè)備提供的方法即可。
在調(diào)用設(shè)備提供的方法時,由于方法的第一個參數(shù)為p_cookie,p_cookie代表了具體的設(shè)備對象,調(diào)用方法時,需要傳遞一個p_cookie給下層,用于在具體實(shí)現(xiàn)時,訪問設(shè)備對象中的具體成員,起到“p_this”的作用。由于在aw_led_set()接口的實(shí)現(xiàn)中,并不需要直接操作具體設(shè)備,因此,無需知道p_cookie的具體類型,僅需起到一個傳遞的作用:在調(diào)用相應(yīng)的方法時,傳遞給下層驅(qū)動使用。
既然要傳遞p_cookie,那么,必然要獲得一個p_cookie并保存下來,顯然,p_cookie代表了具體設(shè)備,只能由具體設(shè)備提供,同時,抽象方法也是由具體設(shè)備提供的,為此,可以將抽象方法和p_cookie定義在一起,形成一個新的類型,以便在具體設(shè)備提供的抽象方法的實(shí)現(xiàn)時,將p_cookie一并提供,即:
為了便于描述,將其稱之為 “LED服務(wù)”。其中包含了由驅(qū)動實(shí)現(xiàn)的抽象方法和傳遞給驅(qū)動函數(shù)的p_cookie。其中,p_servfuncs為指向驅(qū)動虛函數(shù)表的指針,比如,指向
__g_led_gpio_drv_funcs或
__g_led_uart_drv_funcs,p_cookie為指向具體設(shè)備的指針,即傳遞給驅(qū)動函數(shù)的第一個參數(shù)。此時,在aw_led_set()接口的實(shí)現(xiàn)中,無需再完成底層硬件相關(guān)的操作,僅需調(diào)用LED服務(wù)中包含的pfn_led_set方法即可,其范例程序詳見程序清單13.6。
程序清單13.6 aw_led_set()實(shí)現(xiàn)(1)
程序中,使用了一個全局變量__gp_led_serv指向當(dāng)前一個有效的LED服務(wù),顯然,其只有在賦值后才能使用,暫不考慮其如何賦值,僅用以展示pfn_led_set方法的調(diào)用形式。
實(shí)際中,具體的LED設(shè)備往往不止一個。比如,使用GPIO控制的LED設(shè)備和使用UART控制的LED設(shè)備,它們都可以向系統(tǒng)提供LED服務(wù),這就需要系統(tǒng)具有管理多個LED服務(wù)的能力。由于LED設(shè)備的數(shù)目無法確定,可能動態(tài)變化,因此,選用單向鏈表進(jìn)行動態(tài)管理。為此,在struct awbl_led_service中增加一個p_next成員,用于指向下一個LED服務(wù)。即:
此時,系統(tǒng)中的多個LED服務(wù)使用鏈表的形式進(jìn)行管理。那么,在通用接口的實(shí)現(xiàn)中,如何確定具體該使用哪個LED服務(wù)呢?在定義通用接口時,使用了ID號區(qū)分不同的LED,ID號是唯一的,顯然,某一ID的LED必然屬于某一確定的硬件設(shè)備,若一個硬件設(shè)備在提供LED服務(wù)時,包含了該硬件設(shè)備中所有LED的ID號信息,那么,在通用接口的實(shí)現(xiàn)中,就可以根據(jù)ID找到對應(yīng)的LED服務(wù),然后使用驅(qū)動中提供的方法完成LED的操作。為此,可以在LED服務(wù)中再增加一個ID信息,以表示對應(yīng)硬件設(shè)備中所有LED的ID號。
在一個LED硬件設(shè)備中,可能包含多個LED,例如,MiniPort-LED擴(kuò)展板,包含了8個LED,但一般來講,一個LED硬件設(shè)備中所有LED的編號是連續(xù)分配的,基于此,僅需知道一個硬件設(shè)備中LED的起始編號和結(jié)束編號,就可以獲得該硬件設(shè)備中所有LED對應(yīng)的編號,例如,一個硬件設(shè)備中LED的起始編號為2、結(jié)束編號為9,則表示在該硬件設(shè)備中,各個LED的編號分別為:2、3、4、5、6、7、8、9,共計8個LED。為此,可以定義一個LED服務(wù)信息結(jié)構(gòu)體類型,專門用于提供LED服務(wù)相關(guān)的信息,例如:
由此可見,在LED服務(wù)信息中,當(dāng)前僅包含起始編號和結(jié)束編號兩個信息。LED服務(wù)信息是與具體設(shè)備相關(guān)的,因此,可以在LED服務(wù)中新增一個指向LED服務(wù)信息的指針,以便在具體設(shè)備在提供p_cookie和抽象方法的實(shí)現(xiàn)時,將設(shè)備支持的LED編號信息一并提供,LED服務(wù)的完整定義詳見程序清單13.7。
程序清單13.7 完整的LED服務(wù)類型定義(awbl_led.h)
由于在LED服務(wù)中新增了LED編號信息,那么,在通用接口的實(shí)現(xiàn)中,就可以根據(jù)設(shè)備提供的LED編號信息,找到id對應(yīng)的LED服務(wù)?;诖?,aw_led_set()函數(shù)的實(shí)現(xiàn)詳見程序清單13.8。
程序清單13.8 aw_led_set()實(shí)現(xiàn)(2)
程序中,調(diào)用了__led_id_to_serv()函數(shù)以獲取ID號對應(yīng)的LED服務(wù)。__led_id_to_serv()函數(shù)通過遍歷LED服務(wù)鏈表,將id與各個LED服務(wù)中的ID信息進(jìn)行對比,直到找到id對應(yīng)的LED服務(wù)(即id處于該LED服務(wù)的起始編號和結(jié)束編號之間),具體實(shí)現(xiàn)范例詳見程序清單13.9。
程序清單13.9 獲取ID號對應(yīng)的LED服務(wù)
其中,__gp_led_serv_head是一個模塊內(nèi)部使用的全局變量,初始值為NULL,表示初始時系統(tǒng)中無任何有效的LED服務(wù)。同理,可實(shí)現(xiàn)aw_led_toggle()接口,詳見程序清單13.10。
程序清單13.10 aw_led_toggle()實(shí)現(xiàn)
至此,實(shí)現(xiàn)了所有通用接口。顯然,由于當(dāng)前并不存在任何有效的LED服務(wù),因此,
__gp_led_serv_head的值為NULL,致使__led_id_to_serv()的返回值為NULL,最終導(dǎo)致通用接口的返回值始終為-AM_ENODEV。
13.2.4 Method機(jī)制
為了使通用接口能夠操作到具體有效的LED,必須通過某種方法,將當(dāng)前系統(tǒng)中所有LED設(shè)備提供的LED服務(wù)加入到以__gp_led_serv_head為頭的LED服務(wù)鏈表中。
AWbus-lite提供了一種特殊的“Method機(jī)制”,其是一種系統(tǒng)上層和硬件底層相互“交流”的一種方式,可用于系統(tǒng)發(fā)現(xiàn)各個硬件設(shè)備提供的服務(wù)。AWBus-lite提供了Method相關(guān)的宏,詳見表13.2。
表13.2 Method相關(guān)的宏(awbus_lite.h)
1. 定義一個Method類型
AWBL_METHOD_DEF()用于定義一個Method類型,其原型為:
其中,method為定義的Method類型名,string為一個描述字符串,描述字符串僅在定義時對method類型進(jìn)行描述,可以是任意字符串,其它地方不會被使用到。
Method類型具有唯一性,不可定義兩個相同的Method類型。Method類型可以看作一個“唯一標(biāo)識”,用于標(biāo)記某一類操作,在底層驅(qū)動的實(shí)現(xiàn)中,凡是能夠完成該類操作的設(shè)備,都可以使用該“唯一標(biāo)識”標(biāo)記一個入口函數(shù),該入口函數(shù)即用于完成相應(yīng)的操作,這樣一來,系統(tǒng)就可以通過該“唯一標(biāo)識”查找所有被標(biāo)記的入口函數(shù),并依次調(diào)用它們,完成某種特定功能。例如,對于LED,為了獲取當(dāng)前系統(tǒng)中所有設(shè)備提供的LED服務(wù),可以定義一個獲取LED服務(wù)的Method類型,范例程序詳見程序清單13.11。
程序清單13.11 定義Method類型范例程序
如此一來,即定義了一個名為awbl_ledserv_get的Method類型,該Method類型即表示了一類操作:獲取LED服務(wù)。后續(xù)在底層設(shè)備驅(qū)動的實(shí)現(xiàn)中,只要一個設(shè)備能夠提供LED服務(wù),則表示系統(tǒng)可以從中獲取到一個LED服務(wù),此時,該驅(qū)動就可以提供一個入口函數(shù),用于獲取LED服務(wù),并使用該Method類型對入口函數(shù)進(jìn)行標(biāo)記。這樣,在系統(tǒng)啟動時,就可以通過查找系統(tǒng)中所有被該Method類型標(biāo)記的入口函數(shù),然后一一調(diào)用它們,以此獲得所有設(shè)備提供的LED服務(wù)。
2. 定義一個具體的Method對象
定義Method對象的本質(zhì)就是使用Method類型標(biāo)記一個入口函數(shù),使系統(tǒng)知道該入口函數(shù)可以完成某種特定的功能,以便系統(tǒng)在合適的時機(jī)調(diào)用。為便于描述,在AWBus-lite中,將使用Method類型標(biāo)記的入口函數(shù)稱之為一個Method對象。AWBus-lite提供了定義Method對象的輔助宏,其原型為:
其中,name為使用AWBL_METHOD_DEF()定義的Method類型名,handler為用于完成某種特定功能的入口函數(shù)。例如,定義awbl_ledserv_get類型的目的是獲取LED服務(wù),因此,該類型的Method對象對應(yīng)的handler應(yīng)該能夠獲取到一個LED服務(wù)。handler的類型為
awbl_method_handler_t,其定義如下
(awbus_lite.h):
由此可見,awbl_method_handler_t是一個函數(shù)指針類型,其指向的函數(shù)有兩個形參:p_dev和p_arg,返回值為標(biāo)準(zhǔn)的錯誤號。p_dev指向設(shè)備自身,同樣起到一個p_this的作用,該handler運(yùn)行在哪個設(shè)備上,傳入p_dev的值就應(yīng)該為指向該設(shè)備的指針;p_arg為void *類型的參數(shù),其具體類型與該入口函數(shù)需要完成的功能相關(guān),如果功能為獲取一個LED服務(wù),p_arg的實(shí)際類型就為struct awbl_led_service **,即一個指向LED服務(wù)的指針的地址,以便在函數(shù)內(nèi)部改變指向LED服務(wù)的指針的值,使其指向設(shè)備提供的LED服務(wù),從而完成LED服務(wù)的獲取。例如,在GPIO控制LED的設(shè)備中,其能夠提供LED服務(wù),則應(yīng)在對應(yīng)的驅(qū)動中,定義一個具體的Method對象,便于系統(tǒng)得到LED服務(wù)。范例詳見程序清單13.12。
程序清單13.12 定義Method對象范例程序
其中,__g_led_gpio_dev_methods為該設(shè)備能夠提供的Method對象列表,一個設(shè)備提供的Method對象統(tǒng)一存放在一個列表中。該列表的具體使用以及入口函數(shù)的具體實(shí)現(xiàn),將在LED驅(qū)動的實(shí)現(xiàn)中進(jìn)一步介紹。這里僅用于展示系統(tǒng)上層獲取LED服務(wù)的原理。
3. Method對象列表結(jié)束標(biāo)記
在程序清單13.12中,將Method對象定義在了一個列表中,AWBL_METHOD_END用于定義一個特殊的標(biāo)志,表示Method對象列表的結(jié)束。其原型為:
該宏無需傳入任何參數(shù),其僅用于標(biāo)識一個Method對象列表的結(jié)束。例如,GPIO控制的LED設(shè)備只能提供一個Method對象,用于系統(tǒng)上層獲取LED服務(wù),那么,在該對象之后,應(yīng)該使用AWBL_METHOD_END表示列表結(jié)束。范例程序詳見程序清單13.13。
程序清單13.13 AWBL_METHOD_END使用范例程序
4. 導(dǎo)入(聲明)一個在外部定義的Method類型
當(dāng)需要使用一個已定義的Method類型時,若Method類型是在其它文件中定義的,此時就需要在使用前對該Method類型進(jìn)行聲明,類似于C語言中的extern。其原型為:
其中,name為使用AWBL_METHOD_DEF()定義的Method類型名。例如,在程序清單13.13中,定義了Method對象列表,其中使用到了Method類型:awbl_ledserv_get。在使用前,需要對該Method類型進(jìn)行聲明,范例程序詳見程序清單13.14。
程序清單13.14 AWBL_METHOD_IMPORT()使用范例程序
5. 得到一個已定義的Method類型的ID
Method類型相當(dāng)于一個“唯一標(biāo)識”,有時候,需要判斷某一Method對象是否為指定的Method類型。為了便于比較判斷,或?qū)ⅰ癕ethod類型”作為參數(shù)傳遞給其它接口函數(shù),可以通過該宏獲得一個Method類型對應(yīng)的ID,ID作為一個常量,可以用于比較或參數(shù)傳遞。獲取Method類型的ID對應(yīng)的宏原型為:
其中,method為使用AWBL_METHOD_DEF()定義的Method類型名,返回值為該Method類型的ID,其類型為:awbl_method_id_t,該類型的具體定義用戶無需關(guān)心,ID可以用作比較,只要兩個Method類型的ID相同,就表示兩個Method類型是相同的,ID也可以作為參數(shù)傳遞給其它接口,以指定一種Method類型。
例如,在AWbus-lite中,提供了一個工具函數(shù),用于查找設(shè)備中是否存在指定類型的Method對象,其函數(shù)原型為(awbus_lite.h):
其中,p_dev指定了要查找的設(shè)備,即在該設(shè)備中查找是否存在指定類型的Method對象,method用于指定Method類型的ID。若查找到該ID對應(yīng)的method對象,則返回該method對象的入口函數(shù),否則,返回NULL。
例如,有一個p_dev指向的設(shè)備,要查找其是否能夠提供LED服務(wù),則可以通過該接口實(shí)現(xiàn),范例程序詳見程序清單13.15。
程序清單13.15 AWBL_METHOD_ CALL()使用范例程序
程序中,使用AWBL_METHOD_ CALL()得到Method類型awbl_ledserv_get的ID,然后傳遞給awbl_dev_method_get()函數(shù)以查找設(shè)備中是否存在相應(yīng)的Method對象,若存在,則得到了一個有效的入口函數(shù),最后使用該入口函數(shù)即可得到一個LED服務(wù)。
13.2.5 LED服務(wù)鏈表的初始化
通過程序清單13.15所示的一個流程,若一個設(shè)備能夠提供LED服務(wù),則可以從中獲取到相應(yīng)的LED服務(wù)。若對每個設(shè)備都執(zhí)行一遍上述流程,并在獲得一個設(shè)備提供的LED服務(wù)后,就將其添加到以__gp_led_serv_head為頭的LED服務(wù)鏈表中,則可以收集到系統(tǒng)中所有的LED服務(wù),完成LED服務(wù)鏈表的初始構(gòu)建。為了便于對所有設(shè)備執(zhí)行某一操作,AWBus-lite提供了一個用于遍歷所有設(shè)備的接口,其函數(shù)原型為:
其中,pfunc_action表示要在每個設(shè)備上執(zhí)行的操作,p_arg為傳遞給pfunc_action的附加參數(shù),flags為遍歷設(shè)備的標(biāo)志,返回值為標(biāo)準(zhǔn)錯誤號。
pfunc_action的類型為awbl_iterate_func_t,該類型的具體定義如下(awbus_lite.h):
由此可見,awbl_iterate_func_t是一個函數(shù)指針類型,其指向的函數(shù)有兩個形參:p_dev和p_arg,返回值為標(biāo)準(zhǔn)的錯誤號。p_dev指向當(dāng)前遍歷到的設(shè)備,同樣起到一個p_this的作用,當(dāng)前遍歷到哪個設(shè)備,在哪個設(shè)備上運(yùn)行pfunc_action函數(shù),傳入的p_dev就為指向該設(shè)備的指針;p_arg為遍歷時提供的附加參數(shù),其值與調(diào)用awbl_dev_iterate()函數(shù)時傳入的p_arg參數(shù)相同。
flags為遍歷設(shè)備的標(biāo)志,其決定了需要遍歷哪些設(shè)備,以及pfunc_action函數(shù)的返回值是否能夠終止遍歷過程??捎脴?biāo)志詳見表13.3。
表13.3 遍歷設(shè)備標(biāo)志宏(awbus_lite.h)
其中,AWBL_ITERATE_INSTANCES和
AWBL_ITERATE_ORPHANS標(biāo)志用于指定需要遍歷的設(shè)備,即在哪些設(shè)備上執(zhí)行pfunc_action函數(shù)。在硬件設(shè)備列表中,定義了當(dāng)前系統(tǒng)中所有的硬件設(shè)備,當(dāng)設(shè)備具有與之匹配的驅(qū)動時,才能夠變成一個實(shí)例,被系統(tǒng)正常使用,而如果一個設(shè)備沒有與之匹配的驅(qū)動,該設(shè)備將變成一個孤兒設(shè)備,由于沒有與之匹配的驅(qū)動,因此系統(tǒng)暫時無法使用孤兒設(shè)備。
AWBL_ITERATE_INSTANCES表示表示需要遍歷所有實(shí)例,即具有相應(yīng)驅(qū)動的設(shè)備。AWBL_ITERATE_ORPHANS表示需要遍歷所有的孤兒設(shè)備。若要遍歷所有的實(shí)例和孤兒設(shè)備,可以使用或運(yùn)算同時設(shè)定這兩個標(biāo)志。
AWBL_ITERATE_INTRABLE標(biāo)志用于指定
pfunc_action 的返回值是否可以終止遍歷,若設(shè)定了該標(biāo)志,則在某一設(shè)備上運(yùn)行pfunc_action函數(shù)的返回值將可以決定是否終止整個遍歷過程:返回值為AW_OK時,不終止遍歷,繼續(xù)遍歷其它設(shè)備;否則,遍歷過程被終止,不會再繼續(xù)遍歷其它設(shè)備。若未設(shè)定該標(biāo)志,則遍歷過程不受返回值影響,直到遍歷完所有需要遍歷的設(shè)備后結(jié)束。
為了獲得所有設(shè)備提供的LED服務(wù),需要遍歷所有實(shí)例,并在pfunc_action中執(zhí)行如程序清單13.15所示的流程,并將各個設(shè)備提供的LED服務(wù)添加到以__gp_led_serv_head為頭的LED服務(wù)鏈表中。完整的范例程序詳見程序清單13.16。
程序清單13.16 獲取所有設(shè)備提供的LED服務(wù)
程序中,由于孤兒設(shè)備沒有對應(yīng)的驅(qū)動,無法正常使用,顯然無法提供LED服務(wù),因此僅需遍歷所有實(shí)例,遍歷標(biāo)志設(shè)定為了:
AWBL_ITERATE_INSTANCES。該程序的目的是完成LED服務(wù)鏈表的初始構(gòu)建,是一種初始化操作,因此,將其入口函數(shù)命名為了
awbl_led_init(),若需使用LED,則應(yīng)確保在系統(tǒng)啟動時,該函數(shù)被自動調(diào)用。通常情況下,并不需要由用戶手動調(diào)用該函數(shù),而是將該函數(shù)的調(diào)用放在模板工程下的aw_prj_config.c文件中,具體位于aw_prj_early_init()函數(shù)中,該函數(shù)在系統(tǒng)啟動時會被自動調(diào)用,從而使系統(tǒng)在啟動時自動調(diào)用awbl_led_init()函數(shù),詳見詳見程序清單13.17。
程序清單13.17 awbl_led_init()在系統(tǒng)啟動時被自動調(diào)用的原理
在aw_prj_params.h工程配置文件中,只要使能了某一LED設(shè)備,比如,AW_DEV_GPIO_LED,則表示要使用LED,此時,將自動完成AW_COM_AWBL_LED的定義,以此確保當(dāng)使用LED時,awbl_led_init()會在系統(tǒng)啟動過程中被自動調(diào)用。核心的原理性程序詳見程序清單13.18。
程序清單13.18 自動定義AW_COM_AWBL_LED宏的原理(aw_prj_params.h)
至此,完成了LED服務(wù)鏈表的初始化,若系統(tǒng)中存在LED服務(wù),則鏈表將不為空,在LED通用接口的實(shí)現(xiàn)中,只要傳入的id正確,
__led_id_to_serv()的返回值就不為NULL,進(jìn)而返回一個有效的LED服務(wù),接著,通過LED服務(wù)中實(shí)現(xiàn)的抽象方法,即可完成LED相關(guān)的操作,例如,設(shè)置LED狀態(tài)、翻轉(zhuǎn)LED狀態(tài)等。
-
led
+關(guān)注
關(guān)注
240文章
23064瀏覽量
657068 -
嵌入式
+關(guān)注
關(guān)注
5059文章
18974瀏覽量
302065 -
AWorks
+關(guān)注
關(guān)注
1文章
16瀏覽量
5680
原文標(biāo)題:AWorks軟件篇 — 深入理解 AWbus-lite(接口的定義和實(shí)現(xiàn))
文章出處:【微信號:ZLG_zhiyuan,微信公眾號:ZLG致遠(yuǎn)電子】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論