RTT设备驱动框架学习(CAN设备)

RTT设备框架属于组件和服务层,是基于RTT内核之上的上层软件。

设备框架是针对某一类外设,抽象出来的一套统一的操作方法及接入标准,可以屏蔽硬件差异,为应用层提供统一的操作方法。

RTT设备框架分为三层:设备驱动层、设备驱动框架层、I/O设备管理层。

其中设备驱动层直接对接底层硬件设备;I/O设备管理层向应用层提供了rt_device_find、open、read、write、close、register等访问设备的统一标准接口。而设备驱动框架层就是将同类型硬件设备的共同特征抽象出来,并且还预留了接口,可以添加不同设备的独有特性。

其中的设备模型被认为是一类对象,每个设备对象都是由基对象派生的,每个设备都可以继承其父类对象的属性,并派生私有属性。

正是这样的框架,使得RTT设备框架中各模块高内聚低耦合,对于已有的设备类型,只是将底层硬件的驱动对接到设备驱动层。就可以在应用程序中,调用统一的标准接口,使用不同厂家不同类型的硬件设备。

实例分析

设备对象在rtdef.h中的具体定义

c 复制代码
struct rt_device
{
	struct rt_object parent;
	enum rt_device_class_type type;
	rt_uint16_t flag;
	rt_uint16_t open_flag;
	rt_uint8_t ref_count;
	rt_uint8_t device_id;
	 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 */

#ifdef RT_USING_POSIX_DEVIO
    const struct dfs_file_ops *fops;
    struct rt_wqueue wait_queue;
#endif /* RT_USING_POSIX_DEVIO */

    void                     *user_data;                /**< device private data */
};
}

然后从struct rt_device中派生出新的CAN设备类型struct rt_can_device,其中依据CAN类型设备共有的特性新增了一些结构体成员,位于rt-thread\components\drivers\include\drivers\can.h中

c 复制代码
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设备驱动中,又从struct rt_can_device中派生了新的CAN设备模型struct stm32_can,其中添加了这个设备类型的私有数据,便于底层驱动的对接:

c 复制代码
struct stm32_can
{
	char *name;
	CAN_HandleTypeDef CanHandle;
	CAN_FilterTypeDef FilterConfig;
	struct rt_can_device;
};

可以看出,RTT通过结构体和函数指针使用C语言实现了一些面向对象编程的特性,如封装和继承等,这样面向对象、模块化的思维框架,有助于实现各模块之间高内聚低耦合,提高开发效率。

操作方法

在struct rt_can_device中可以看到针对CAN设备有以下操作方法,这些操作方法是需要我们在设备驱动层去针对不同的硬件设备进行对接实现的。对于一些特殊的设备类型,可以不用对接其所有的操作方法。

c 复制代码
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);
};

在drv_can.c中,就实现了所有CAN设备的操作方法,并赋值给对应的函数指针,可以直接调用。并且通过static const修饰符,使结构体变量的内容是固定的,提高了代码的安全性和可维护性。然后通过rt_hw_can_register注册。

c 复制代码
static const struct rt_can_ops _can_ops = 
{
	_can_config,
    _can_control,
    _can_sendmsg,
    _can_recvmsg,
};
c 复制代码
rt_err_t rt_hw_can_register(struct rt_can_device *can, const char *name, const struct rt_can_ops *ops, void *data);
c 复制代码
rt_hw_can_register(&drv_can1.device, drv_can1.name, &_can_ops, &_can_ops, &drv_can1);

其中最后一个参数为void类型指针,在注册同类型的不同设备时,就可以通过最后一个参数,在注册时传入其特有的私有数据。例如STM32的drv_can中传入的就是stm32_can结构体类型,其中就包含了stm_can的私有数据域,在对接底层硬件驱动的时候就会方便很多。

相关推荐
小码的头发丝、32 分钟前
Django中ListView 和 DetailView类的区别
数据库·python·django
幼儿园老大*40 分钟前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
Karoku06642 分钟前
【企业级分布式系统】Zabbix监控系统与部署安装
运维·服务器·数据库·redis·mysql·zabbix
为什么这亚子1 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
1 小时前
开源竞争-数据驱动成长-11/05-大专生的思考
人工智能·笔记·学习·算法·机器学习
ctrey_1 小时前
2024-11-4 学习人工智能的Day21 openCV(3)
人工智能·opencv·学习
~yY…s<#>1 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
啦啦右一1 小时前
前端 | MYTED单篇TED词汇学习功能优化
前端·学习
周全全1 小时前
MySQL报错解决:The user specified as a definer (‘root‘@‘%‘) does not exist
android·数据库·mysql
白云如幻1 小时前
MySQL的分组函数
数据库·mysql