6

我正在开发一个依赖于一些外部硬件的嵌入式 C 项目。我希望删除访问这些部分的代码,这样我就可以在不使用任何硬件的情况下模拟系统。到目前为止,我已经使用了一些宏,但这迫使我对我的生产代码进行一些更改,我想避免这种情况。

例子:

stub.h
#ifdef _STUB_HW
#define STUB_HW(name) Stub_##name
#else /*_STUB_HW*/
#define STUB_HW(name) name
#endif /*_STUB_HW*/

my_hw.c
WORD STUB_HW(clear_RX_TX)()
{ /* clear my rx/tx buffer on target HW */ }

test_my_hw.c
#ifdef _STUB_HW
WORD clear_RX_TX()
{ /* simulate clear rx/tx buffer on target HW */ }

使用此代码,我可以使用预处理器标签打开/关闭存根有_STUB_HW

没有一种方法可以完成此操作而无需更改我的产品代码,并避免大量 ifdefs。如果可以避免的话,我不会在同一个文件中混合 prod 和 test 代码。我不在乎测试代码看起来如何,只要我可以尽可能多地避开生产代码。

编辑:

如果可以在不替换整个文件的情况下选择/重命名函数,那就太好了。就像把所有函数都从开始nRF_##并给出一个新名称然后插入test_nRF_##nRF_##它是可能的

4

3 回答 3

9

我只是制作了两个文件 ActualDriver.c 和 StubDriver.c 包含完全相同的函数名。通过将生产代码与不同对象链接起来的两个构建,没有命名冲突。这样,生产代码不包含测试或条件代码。

于 2009-01-06T09:13:57.967 回答
1

正如 Gerhard 所说,使用一个通用的头文件“driver.h”和包含实际函数和存根函数的单独硬件层实现文件。

在 Eclipse 中,我有两个目标,我“从构建中排除”不使用的 driver.c 文件,并确保构建中包含正确的目标。然后 Eclipse 在构建时生成 makefile。

要指出的另一个问题是确保您定义了固定大小的整数,以便您的代码从溢出的角度来看是相同的。(尽管从您的代码示例中我可以看到您正在这样做。)

于 2009-01-06T12:40:58.203 回答
1

我同意以上所述。对此的标准解决方案是定义一组不透明的抽象函数调用,它们是硬件的“驱动程序”,然后在主程序中调用它。然后提供两种不同的驱动实现,一种用于hw,一种用于sw。sw 变体将以某种适当的方式模拟硬件的 IO 效果。

请注意,如果目标是在较低级别,即编写要模拟每个硬件访问而不是整个函数的代码,则可能会有点棘手。但是在这里,可以定义不同的“write_to_memory”和“read_from_memory”函数(或宏,如果目标速度很重要)。

在这两种情况下都不需要更改函数的名称,只需有两个不同的批处理文件、make 文件或 IDE 构建目标(取决于您使用的工具)。

最后,在许多情况下,更好的技术解决方案是使用成熟的目标系统模拟器,例如QemuSimicsSystemCCoWareVaST或类似的。这使您可以始终运行相同的代码,而是构建一个从软件的角度来看与实际硬件一样工作的硬件模型。它确实需要更大的前期投资,但对于许多项目来说,这是非常值得的。它基本上摆脱了为目标和主机构建不同版本的讨厌问题,并确保您始终使用带有部署构建选项的交叉编译器。请注意,许多嵌入式编译器套件都内置了一些基本的此类模拟能力。

于 2009-01-09T08:12:31.067 回答