前言介紹
RT-Thread 設(shè)備框架屬于組件和服務(wù)層,是基于 RT-Thread 內(nèi)核之上的上層軟件。設(shè)備框架是針對(duì)某一類外設(shè),抽象出來的一套統(tǒng)一的操作方法及接入標(biāo)準(zhǔn),可以屏蔽硬件差異,為應(yīng)用層提供統(tǒng)一的操作方法。
RT-Thread 設(shè)備框架分為三層:設(shè)備驅(qū)動(dòng)層、設(shè)備驅(qū)動(dòng)框架層、I/O 設(shè)備管理層。其中設(shè)備驅(qū)動(dòng)層直接對(duì)接底層硬件設(shè)備;I/O 設(shè)備管理層向應(yīng)用層提供了rt_device_find、open、read、write、close、register等訪問設(shè)備的統(tǒng)一標(biāo)準(zhǔn)接口。而設(shè)備驅(qū)動(dòng)框架層就是就是將同類型硬件設(shè)備的共同特特征提取抽象出來,并且還預(yù)留了接口,可以添加不同設(shè)備的獨(dú)有特性。
其中的設(shè)備模型被認(rèn)為是一類對(duì)象,每個(gè)設(shè)備對(duì)象都是由基對(duì)象派生的,每個(gè)設(shè)備都可以繼承其父類對(duì)象的屬性,并派生其私有屬性。
正是這樣的框架,使得 RT-Thread 設(shè)備框架中各模塊高內(nèi)聚低耦合,對(duì)于已有的設(shè)備類型,只要將底層硬件的驅(qū)動(dòng)對(duì)接到設(shè)備驅(qū)動(dòng)層,就可以在應(yīng)用程序中,調(diào)用統(tǒng)一的標(biāo)準(zhǔn)接口,使用的不同廠家不同類型的硬件設(shè)備。
示例分析
下文將以 CAN 設(shè)備為例,并從 void 類型指針、結(jié)構(gòu)體等方向,分析 RT-Thread 設(shè)備驅(qū)動(dòng)框架。
設(shè)備對(duì)象
以下是設(shè)備對(duì)象在 rt-threadincludertdef.h 中的具體定義:(去除了其中一些擴(kuò)展的功能,方便理解)
/**
Device structure
*/
struct rt_device
{
struct rt_object parent; / *< inherit from rt_object /
enum rt_device_class_type type; / < device type */
rt_uint16_t flag; / < device flag /
rt_uint16_t open_flag; / < device open flag */
rt_uint8_t ref_count; / < reference count /
rt_uint8_t device_id; / < 0 - 255 /
/ device call back */
rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);
#ifdef RT_USING_DEVICE_OPS
const struct rt_device_ops ops;
#else
/ common device interface */
rt_err_t (*init) (rt_device_t dev);
rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag);
rt_err_t (*close) (rt_device_t dev);
rt_ssize_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_ssize_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
rt_err_t (*control)(rt_device_t dev, int cmd, void args);
#endif / RT_USING_DEVICE_OPS */
void *user_data; /< device private data */
};
然后從 struct rt_device 中派生出新的 CAN 設(shè)備類型 struct rt_can_device ,其中依據(jù) CAN 類型設(shè)備共有的特性新增了一些結(jié)構(gòu)體成員,位于rt-threadcomponentsdriversincludedriverscan.h 中:
struct rt_can_device
{
struct rt_device parent;
const struct rt_can_ops *ops;
struct can_configure config;
struct rt_can_status status;
rt_uint32_t timerinitflag;
struct rt_timer timer;
struct rt_can_status_ind_type status_indicate;
#ifdef RT_CAN_USING_HDR
struct rt_can_hdr *hdr;
#endif
#ifdef RT_CAN_USING_BUS_HOOK
rt_can_bus_hook bus_hook;
#endif / RT_CAN_USING_BUS_HOOK /
struct rt_mutex lock;
void *can_rx;
void *can_tx;
};
在 stm32 的 CAN 設(shè)備驅(qū)動(dòng)中,又從 struct rt_can_device 中派生出了新的 CAN 設(shè)備模型 struct stm32_can 其中添加了這個(gè)設(shè)備類型的私有數(shù)據(jù),便于底層驅(qū)動(dòng)的對(duì)接:
/* stm32 can device */
struct stm32_can
{
char name;
CAN_HandleTypeDef CanHandle;
CAN_FilterTypeDef FilterConfig;
struct rt_can_device device; / inherit from can device */
};
可以看出,RT-Thread 通過結(jié)構(gòu)體和函數(shù)指針使用 C 語言實(shí)現(xiàn)了一些面向?qū)ο?a target="_blank">編程的特性,如封裝和繼承等,這樣面向?qū)ο?、模塊化的思維框架,有助于實(shí)現(xiàn)各模塊之間高內(nèi)聚低耦合,提高開發(fā)效率。
操作方法
在 rt-threadcomponentsdriversincludedriverscan.h 中可以看到針對(duì) CAN 設(shè)備有以下操作方法,這些操作方法是需要我們?cè)谠O(shè)備驅(qū)動(dòng)層去針對(duì)不同的硬件設(shè)備進(jìn)行對(duì)接實(shí)現(xiàn)的。對(duì)于一些特殊的設(shè)備類型,可以不用對(duì)接其所有的操作方法。
struct rt_can_ops
{
rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg);
rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg);
int (*sendmsg)(struct rt_can_device *can, const void *buf, rt_uint32_t boxno);
int (*recvmsg)(struct rt_can_device *can, void *buf, rt_uint32_t boxno);
};
在librariesHAL_Driversdrv_can.c中,就實(shí)現(xiàn)了所有 CAN 設(shè)備的操作方法,并賦值給對(duì)應(yīng)的函數(shù)指針,可以直接調(diào)用。并且通過 static const 修飾符,使結(jié)構(gòu)體變量_can_ops的值在編譯時(shí)被確定,并且不能在程序運(yùn)行時(shí)修改。這樣可以確保該結(jié)構(gòu)體變量的內(nèi)容是固定的,提高了代碼的安全性和可維護(hù)性。然后通過rt_hw_can_register注冊(cè)。
static const struct rt_can_ops _can_ops =
{
_can_config,
_can_control,
_can_sendmsg,
_can_recvmsg,
};
/* register CAN1 device */
rt_hw_can_register(&drv_can1.device,
drv_can1.name,
&_can_ops,
&drv_can1);
可以看一下rt_hw_can_register函數(shù)的具體聲明:
rt_err_t rt_hw_can_register(struct rt_can_device *can,
const char *name,
const struct rt_can_ops *ops,
void *data);
其中最后一個(gè)參數(shù)為 void 類型指針,在注冊(cè)同類型的不同設(shè)備時(shí),就可以通過最后一個(gè)參數(shù),在注冊(cè)時(shí)傳入其特有的私有數(shù)據(jù)。例如 STM32 的 drv_can 中傳入的就是 stm32_can結(jié)構(gòu)體類型,其中就包含了 stm32 can 的私有數(shù)據(jù)域,在對(duì)接底層硬件驅(qū)動(dòng)的時(shí)候就會(huì)方便很多。
總結(jié)
可以感受到,其中結(jié)構(gòu)體和指針的運(yùn)用是非常重要的。盡管C語言是一種面向過程的語言,但通過使用結(jié)構(gòu)體和函數(shù)指針,可以模擬實(shí)現(xiàn)封裝、繼承和多態(tài)這三個(gè)面向?qū)ο缶幊痰奶匦?,享受面向?qū)ο缶幊痰暮锰帯?/p>
對(duì)于指針的運(yùn)用,主要是 void 類型指針和函數(shù)指針。由于 void 指針沒有特定的類型,因此它可以指向任何類型的數(shù)據(jù)。也就是說,任何類型的指針都可以直接賦值給 void 指針,而無需進(jìn)行其他相關(guān)的強(qiáng)制類型轉(zhuǎn)換,便于傳遞同類型的不同設(shè)備的私有數(shù)據(jù)。通過函數(shù)指針,也就是回調(diào)函數(shù),可以大大提高程序的靈活性和并起到封裝的作用。
-
驅(qū)動(dòng)器
+關(guān)注
關(guān)注
51文章
7997瀏覽量
145007 -
CAN總線
+關(guān)注
關(guān)注
145文章
1898瀏覽量
130333 -
STM32
+關(guān)注
關(guān)注
2257文章
10828瀏覽量
352444 -
C語言
+關(guān)注
關(guān)注
180文章
7575瀏覽量
134028 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1239瀏覽量
39427
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論