我目前正在开发一个嵌入式系统项目,该项目在三种硬件模型上使用相同的 C99 代码库。这些模型之间的主要区别封装在存储传感器映射的常量数组中。下面是一个简化的示例,说明了每个硬件型号的配置:
// Configuration example
#if defined(MODEL_A)
// Configuration for Model A
#define PRODUCT_CODE 1
#define NUMBER_OF_SENSORS 5
const int temperature_sensor_map[NUMBER_OF_SENSORS] = { 0, 1, 2, 3, 4 };
#elif defined(MODEL_B)
// Configuration for Model B
#define PRODUCT_CODE 2
#define NUMBER_OF_SENSORS 3
const int temperature_sensor_map[NUMBER_OF_SENSORS] = { 0, 2, 4 };
#define NUMBER_OF_SENSORS 3
#elif defined(MODEL_C)
// Configuration for Model C
// ...
#else
#error Define MODEL_A, MODEL_B, or MODEL_C
#endif
为了改进这些配置的管理并便于跟踪 Git 中的更改,我正在考虑将配置分解为多个文件,每个文件都针对特定的硬件模型进行定制。然而,这种方法需要创建七个文件,这似乎过于复杂:
- config.h (Main configuration header)
- config_model_a.h and config_model_a.c (Configuration for Model A)
- config_model_b.h and config_model_b.c (Configuration for Model B)
- config_model_c.h and config_model_c.c (Configuration for Model C)
下面是代码示例。
注意:如下所示,全局变量的使用不是问题,因为该项目中使用的自定义调试器有一定的限制,只能检查全局变量。
// File config.h
#ifndef CONFIG_H
#define CONFIG_H
#if defined(MODEL_A)
#include "config_model_a.h"
#elif defined(MODEL_B)
#include "config_model_b.h"
#elif defined(MODEL_C)
#include "config_model_c.h"
#else
#error Define MODEL_A, MODEL_B, or MODEL_C
#endif
extern const int temperature_sensor_map[];
#endif // End of include guard
// File config_model_a.h
#define PRODUCT_CODE 1
#define NUMBER_OF_SENSORS 5
// File config_model_a.c
#if defined(MODEL_A)
const int temperature_sensor_map[NUMBER_OF_SENSORS] = { 0, 1, 2, 3, 4 };
#endif
// File config_model_b.h
#define PRODUCT_CODE 2
#define NUMBER_OF_SENSORS 3
// File config_model_b.c
#if defined(MODEL_B)
const int temperature_sensor_map[NUMBER_OF_SENSORS] = { 0, 2, 4 };
#endif
模型 C 的文件遵循类似的模式
但是,我正在探索不依赖构建系统并维护干净、可移植代码的替代方法。具体来说,我对无需多个包含文件或 .c 文件的解决方案感兴趣。
您有不依赖于构建系统的建议吗?
(我不想依赖构建系统,因为我们目前使用 Eclipse CDT,但计划将来过渡到 CMake,并且我希望该解决方案能够在两个系统中工作)
如果您不想依赖 buid 系统,一种解决方案是在运行时进行配置。 为此,您的软件需要能够识别硬件型号(例如,为每个型号使用不同的分压器)。
这个想法是创建一个接口,供需要读取传感器的软件组件使用。然后,您创建一对 .h/.c 配置文件,在其中提供获取正确传感器的函数。
// sensor_config.h
// Enum with models
typedef enum {
MODEL_A,
MODEL_B,
// ...
} model_t;
// Your interface
typedef struct {
int (*get_product_code)(void);
int (*get_number_of_sensors)(void);
int (*get_sensor_map_at)(int);
} sensor_config_t ;
// Getter
sensor_config_t* get_sensor_config(model_t model);
// other models...
还有 .c 文件
// sensor_config.c
// Model A
#define N_SENSORS_A 5
static int get_product_code_model_a(void);
static int get_number_of_sensors_model_a(void);
static int get_sensor_at_model_a(int sensor_id);
static sensor_config_t sensor_a
{
&get_product_code_model_a,
&get_number_of_sensors_model_a,
&get_sensor_at_model_a
};
static int get_product_code_model_a(void)
{
return 1;
}
static int get_number_of_sensors_model_a(void)
{
return N_SENSORS_A;
}
static int get_sensor_at_model_a(int sensor_id)
{
static const int mapping[N_SENSORS_A] = {0, 1, 2, 3, 4};
// TODO: check index...
return mapping[sensor_id];
}
// Model B
#define N_SENSORS_B 3
static int get_product_code_model_b(void);
static int get_number_of_sensors_model_b(void);
static int get_sensor_at_model_b(int sensor_id);
static sensor_t sensor_b
{
&get_product_code_model_b,
&get_number_of_sensors_model_b,
&get_sensor_at_model_b
};
static int get_product_code_model_b(void)
{
return 2;
}
static int get_number_of_sensors_model_b(void)
{
return N_SENSORS_B;
}
static int get_sensor_at_model_b(int sensor_id)
{
static const int mapping[N_SENSORS_B] = {0, 2, 4};
// TODO: check index...
return mapping[sensor_id];
}
// other models...
// Getter
sensor_config_t* get_sensor_config(model_t model)
{
if (model == MODEL_A)
{
return &sensor_a;
}
else if (model == MODEL_B)
{
return &sensor_b;
}
else
{
// More models...
}
return NULL;
}
在配置/读取传感器之前,软件会读取硬件模型并获取正确的传感器。
// main.c
#include "sensor_interface.h"
#include "sensor_config.h"
// Your sensor object
sensor_config_t* my_sensor_config = NULL;
void main(void){
// Assign the right sensor config depending on the model
model_t hw_model = read_hw_model(); // Read voltage from divider and deduct model
my_sensor_config = get_sensor_config(hw_model);
// TODO : check that my_sensor_config is not NULL...
while(1)
{
// Do something with the sensor config
int product_code = my_sensor_config->get_product_code();
int n_sensors = my_sensor_config->get_number_of_sensors();
int first_sensor = my_sensor_config->get_sensor_at(0);
int second_sensor = my_sensor_config->get_sensor_at(1);
// ...
}
}