【问题标题】:Program organization with device drivers in C使用 C 语言的设备驱动程序组织程序
【发布时间】:2015-06-06 13:18:14
【问题描述】:

假设我有两个设备驱动程序,我希望它们共享同一个接口,这样调用者就不会知道它正在与哪个驱动程序准确通信。我将如何在 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 命令运行的调制解调器。

【问题讨论】:

  • @Olaf 我已在 OP 中添加了有关我的系统的详细信息。
  • 关于您的编辑 - 第三种方法是要走的路。 IDE 可能提供了一个简单的切换选项,例如单选按钮。

标签: c driver organization


【解决方案1】:

所有三个变体实际上都是有用的。选择哪一个取决于您的实际需要:

  1. 从调用方选择驱动程序会将两个驱动程序添加到代码中。只有在运行时切换驱动程序才有意义。那么这将是(唯一)要走的路。使用例如提供接口的函数指针或两个相同的const structs(函数指针和可能的其他数据)。
  2. 全局开关很丑陋,而且不可能跨函数和声明。更好的是使用#if .. #elif #end 进行条件编译。如果两个驱动程序只有很小的差异,这是有道理的,例如不同的 SPI 接口(SPI1 与 SPI2 ...)。那么这就是要走的路。通过构建工具的一些努力,您甚至可以将其用于案例 1。(一个文件用于两个不同的驱动程序,但我不建议这样做)。
  3. 如果两个驱动程序的实现有很大不同,但具有相同的接口,请采用第三种方法,但使用单个标头或两个驱动程序(见下文)。

请注意,除了第一种方法之外,两个驱动程序都必须为应用程序提供一个相同的接口。第一种方法实际上允许差异,但这实际上需要用户代码对它们进行不同的处理,这可能不是您想要的。 为两个驱动程序使用单个头文件(例如:“spi_memory.h”和“spi_flash.c”与“spi_eeprom.c”)确实确保应用程序看不到实际差异 - 只要驱动程序也 当然,行为完全相同。界面中的变量(例如extern size_t memory_size;)或函数(更好的方法)可以捕捉到细微的差异。

【讨论】:

    【解决方案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,然后在运行时决定(甚至在运行中更改它,无论出于何种原因)。

    【讨论】:

    • 我喜欢函数指针的优雅,但我不需要在运行时在驱动程序之间切换(也不能同时适应两者)。
    猜你喜欢
    • 2017-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-23
    • 2011-04-14
    • 1970-01-01
    • 2014-09-04
    相关资源
    最近更新 更多