使用C中的设备驱动程序组织程序

时间:2015-06-06 13:18:15

标签: c driver organization

假设我有两个设备驱动程序,我希望它们共享相同的界面,这样调用者就不知道它正在与哪个驱动程序进行通信。我如何在C中组织这个?我想过几个方法:

首先:为具有相同接口的两个驱动程序创建一对.c / .h文件,并在调用者中创建一个开关:

//main.c:

#ifdef USING_DRIVER_1
 #include "driver_1.h"
#else
 #include "driver_2.h"
#endif // USING_DRIVER_1

第二:使用单个标题并在驱动程序的源文件中创建一个文件长开关,如下所示:

//driver_1.c:

#ifdef USING_DRIVER_1
#include "driver.h"

bool func(uint32_t var)
{
    foo(var);
}
#endif // USING_DRIVER_1

//driver_2.c:

#ifndef USING_DRIVER_1
#include "driver.h"

bool func(uint32_t var)
{
    bar(var);
}
#endif // !USING_DRIVER_1

第三:这个与第二个很相似,但不是在文件本身中使用switch语句,而是在makefile或IDE中选择特定的驱动程序:

#makefile:

SRC = main.c
#SRC += driver_1.c
SRC += driver_2.c

我敢肯定其中一个优于其他人,可能还有一些我没想过。它在实践中是如何完成的?

编辑:

有关我的特定系统的详细信息:我的目标是ARM微控制器和我的开发人员。环境是一个IDE。设备驱动程序用于两个不同的修订版,并且永远不会同时使用,因此每个版本应该只包含一个版本。设备本身是通过AT命令运行的调制解调器。

2 个答案:

答案 0 :(得分:2)

我建议使用指向函数的指针。例如:

struct driver_api {
    bool (*pFunc)(uint32_t);
} DriverApi;
void initializeApi(struct driver_api *pApi);

// driver1.c:
void initializeApi(struct driver_api *pApi)
{
    pApi->pFunc = bar;
}
// driver2.c:
void initializeApi(struct driver_api *pApi)
{
    pApi->pFunc = foo;
}

您可能考虑的另一件事是从源文件中删除#ifndef USING_DRIVER_1个检查。使用构建系统(例如make)并指定项目中应包含哪些源文件。然后,基于某些编译时选项(例如命令行参数)包括driver1.cdriver2.c,但不包括两者。

指针的“优点”是你可以编译两个API,然后在运行时决定(甚至在运行中改变它,无论出于何种原因)。

答案 1 :(得分:2)

这三种变体实际上都很有用。选择哪个取决于您实际需要的内容:

  1. 从调用者中选择驱动程序会将两个驱动程序添加到代码中。只有在运行时切换驱动程序才有意义。然后它将是(唯一的)方式。使用例如函数指针或两个相同的const struct,它们提供接口(函数指针和可能的其他数据)。
  2. 全局切换很简单,不能跨函数和声明。更好的是使用#if .. #elif #end进行条件编译。如果两个驱动程序只有很小的差异,例如,这是有道理的。不同的SPI接口(SPI1与SPI2 ......)。那么这就是要走的路。通过构建工具的一些努力,您甚至可以将其用于案例1.(一个文件用于两个不同的驱动程序,但不是我的建议)。
  3. 如果两个驱动程序的实现差异很大,但具有相同的接口,请采用第三种方法,但使用单个标头或两个驱动程序(见下文)。
  4. 除了第一种方法之外的所有方法,两个驱动程序都必须为应用程序提供相同的接口。第一种方法实际上允许存在差异,但这实际上需要用户代码将它们区别对待并且可能不是您想要的。 对两个驱动程序使用单个头文件(例如:" spi_memory.h"" spi_flash.c" vs." spi_eeprom.c")确保应用程序确实没有看到实际的差异 - 当然,只要驱动程序行为相同。接口中的变量(例如extern size_t memory_size;)或函数(更好的方法)可以捕捉到微小的差异。