RT-thread中采用了对容器的方式来存储系统中的各种类型的对象
今天来解析一下device对象,device对象是对系统中设备的一种抽象,同时也是从所有对象的基类object派生而来,定义的数据结构为:
struct rt_device
{
struct rt_object parent; /**< inherit from rt_object */
enum rt_device_class_type type; /**< device type */
rt_uint16_t flag, open_flag; /**< device flag and device open flag */
/* 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);
/* 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_size_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_size_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, rt_uint8_t cmd, void *args);
#ifdef RT_USING_DEVICE_SUSPEND
rt_err_t (*suspend) (rt_device_t dev);
rt_err_t (*resumed) (rt_device_t dev);
#endif
void *user_data; /**< device private data */
};
可以看出其结构中最前面的字段为struct rt_object parent,说明其也是一个rt_object 对象,这个相当于面向对象中的继承关系
同时在内部还定义了一套统一操作函数,类似于linux中把所有的设备操作看成文件操作一样,linux中也有一套操作文件的接口
device只是一种抽象,如果落实到具体的一种设备上时,根据继承的原理,只要从抽像的device设备派生就可以了,比如系统中有串口设备,则可以定义成如下的结构表示串口设备:
struct rt_at91serial
{
struct rt_device parent;
struct rt_at91serial_hw* hw_base;
rt_uint16_t peripheral_id;
rt_uint32_t baudrate;
/* reception field */
rt_uint16_t save_index, read_index;
rt_uint8_t rx_buffer[RT_UART_RX_BUFFER_SIZE];
};
如果你的设备有两个串口,则只要创建两个串口实例就ok了,比如:
#ifdef RT_USING_UART1
struct rt_at91serial serial1;
#endif
#ifdef RT_USING_UART2
struct rt_at91serial serial2;
#endif
但是C语言中不支持构造和析构函数,所以在创建实例的时候,不会自动调用到初始化函数,所以在创建完两个串口实例后,需要初始化一把,主要是把真正的处理函数挂接到统一的处理函数上,相当于是实现了面向对象中的多态,当上层应用程序调用统一的open、read、write接口时,实际上会调用到真的设备处理函数上,见下面的初始化函数:
rt_err_t rt_hw_serial_init()
{
rt_device_t device;
#ifdef RT_USING_UART1
device = (rt_device_t) &serial1;
/* init serial device private data */
serial1.hw_base = (struct rt_at91serial_hw*)AT91C_BASE_US0;
serial1.peripheral_id = AT91C_ID_US0;
serial1.baudrate = 115200;
/* set device virtual interface */
device->init = rt_serial_init;
device->open = rt_serial_open;
device->close = rt_serial_close;
device->read = rt_serial_read;
device->write = rt_serial_write;
device->control = rt_serial_control;
/* register uart1 on device subsystem */
rt_device_register(device, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
#endif
#ifdef RT_USING_UART2
device = (rt_device_t) &serial2;
serial2.hw_base = (struct rt_at91serial_hw*)AT91C_BASE_US1;
serial2.peripheral_id = AT91C_ID_US1;
serial2.baudrate = 115200;
/* set device virtual interface */
device->init = rt_serial_init;
device->open = rt_serial_open;
device->close = rt_serial_close;
device->read = rt_serial_read;
device->write = rt_serial_write;
device->control = rt_serial_control;
/* register uart2 on device subsystem */
rt_device_register(device, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
#endif
return RT_EOK;
}
所有到这里,一个设备的驱动程序编写可以转化实现以下几个处理函数
device->init = rt_serial_init;
device->open = rt_serial_open;
device->close = rt_serial_close;
device->read =rt_serial_read;
device->write = rt_serial_write;
device->control = rt_serial_control
这也是RT-thread编写驱动程序的一个框架,其应该是借鉴了linux中的实现方式
linux设备驱动程序这本书没有怎么看过,找个时间要好好的研究一下!