我正在开发一个依赖于某些外部硬件的嵌入式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
打开/关闭存根
有没有办法在不必更改我的prod代码和避免大量ifdef的情况下完成此操作。如果我可以避免,我不会在同一个文件中混合使用prod和test代码。我不关心测试代码的外观,只要我能尽可能多地保留生产代码。
如果可以在不替换整个文件的情况下选择/重命名函数,那将会很好。就像从nRF_##
开始,然后给出一个新名称,然后将test_nRF_##
插入nRF_##
(如果它是可行的)
答案 0 :(得分:9)
我只创建两个文件ActualDriver.c和StubDriver.c,它们包含完全相同的函数名称。通过将生产代码与不同对象相关联的两个构建,没有命名冲突。这样,生产代码不包含测试或条件代码。
答案 1 :(得分:1)
正如Gerhard所说,使用公共头文件“driver.h”和单独的包含实际和存根函数的硬件层实现文件。
在eclipse中,我有两个目标,我“从构建中排除”不使用的driver.c文件,并确保构建中包含正确的文件。 Eclipse然后在构建时生成makefile。
要指出的另一个问题是确保定义固定大小的整数,以便从溢出角度看代码的行为相同。 (虽然从您的代码示例中我可以看到您正在这样做。)
答案 2 :(得分:1)
我同意上述内容。对此的标准解决方案是定义一组不透明的函数调用,它们是hw的“驱动程序”,然后在主程序中调用它。然后提供两种不同的驱动程序实现,一种用于hw,一种用于sw。 sw变体将以某种适当的方式模拟hw的IO效果。
请注意,如果目标是较低级别,即编写要模拟每个硬件访问的代码而不是整个函数,则可能有点过时。但是在这里,可以定义不同的“write_to_memory”和“read_from_memory”函数(或宏,如果目标上的速度是必要的)。
在任何一种情况下都不需要更改函数名称,只需要两个不同的批处理文件,make文件或IDE构建目标(取决于您使用的工具)。
最后,在许多情况下,更好的技术解决方案是使用完整的目标系统模拟器,例如Qemu,Simics,SystemC,CoWare, VaST或类似的。这使您可以始终运行相同的代码,而是从软件的角度构建一个与实际硬件类似的硬件模型。它确实需要更大的前期投资,但对于许多项目来说,这是值得的。它基本上摆脱了为目标和主机提供不同构建的令人讨厌的问题,并确保始终将交叉编译器与部署构建选项一起使用。请注意,许多嵌入式编译器套件都内置了一些基本的模拟功能。