对高通代码结构以及编写技巧的学习和总结,不断更新…

数组和枚举定义的另类写法

用列表的形式去表示数组和枚举类型

优点

方便后期添加新值,便于维护。增加一个值,不必去考虑数组或者枚举的大小,也不用去考虑位置和顺序。

//枚举类型
#define AEC_CORE_GET_ENUM_LIST(ADD_ENTRY) \
ADD_ENTRY(AEC_GET_EXPOSURE_PARAMS) /* Mask to get aec info. */ \
ADD_ENTRY(AEC_GET_META_INFO) /* Mask to get meta info. */ \
ADD_ENTRY(AEC_GET_REAL_GAIN_FROM_ISO) \
ADD_ENTRY(AEC_GET_STATS_REQUIRED) /* Mask to get stats type required */ \
ADD_ENTRY(AEC_GET_UNIFIED_FLASH) \
ADD_ENTRY(AEC_GET_RGN_SKIP_PATTERN) \
ADD_ENTRY(AEC_GET_RELOAD_EXPOSURE_PARAMS) \
ADD_ENTRY(AEC_GET_LED_CAL_CONFIG) \
ADD_ENTRY(AEC_GET_MAX)

#define AEC_CORE_GENERATE_ENUM(ENUM) ENUM,
typedef enum
{
AEC_CORE_GET_ENUM_LIST(AEC_CORE_GENERATE_ENUM)
} aec_core_get_enum_type;
//字符串数组
#define AEC_SET_PARAM_ENUM_LIST(ADD_ENTRY) \
ADD_ENTRY(AEC_SET_PARAM_INVALID) \
ADD_ENTRY(AEC_SET_PARAM_INIT_CHROMATIX_SENSOR) \
ADD_ENTRY(AEC_SET_PARAM_EXP_COMPENSATION) \
ADD_ENTRY(AEC_SET_PARAM_BRIGHTNESS_LVL) \
ADD_ENTRY(AEC_SET_PARAM_MAX)

//# 是把参数字符串化,## 是将两个参数连为一个整体
#define AEC_PARAM_GENERATE_STRING(STRING) #STRING,
static char *aec_biz_set_param_strings[AEC_SET_PARAM_MAX+1] = {
AEC_SET_PARAM_ENUM_LIST(AEC_PARAM_GENERATE_STRING)
};
//获取数组值(eventId的值)
return aec_biz_set_param_strings[eventId < AEC_SET_PARAM_MAX ?

eventId : AEC_SET_PARAM_MAX];

用union去定义接口结构体

优点

  • 用union只需要最大的值的空间,节省空间。

  • 加上type,可以利用switch对不同类型的请求做处理,在union中取相应的数

typedef struct
{
aec_set_enum_type type; /**< */
union
{
aec_set_parameter_init_t init_param;
aec_bracket_t aec_bracket;
int32 video_hdr; /**< */
aec_core_hdr_type snapshot_hdr;
aec_precapture_trigger_t aec_trigger;
boolean est_for_af;
aec_algo_ramp_test_type ramp_test;
} u;
} aec_core_set_param_type;

用函数指针实现多态

优点

  • 扩展性:把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
//c文件
//函数定义
boolean aec_biz_set_param(aec_set_parameter_t *param,
aec_output_data_t *output, uint8_t num_of_outputs, void *aec_obj){ …… }

void aec_biz_load_function(aec_object_t *aec_object)

{

if (!aec_object) {
return NULL;
}
aec_object->set_parameters = aec_biz_set_param;
aec_object->get_parameters = aec_biz_get_param;
aec_object->process = aec_biz_process;
aec_object->init = aec_biz_init;
aec_object->deinit = aec_biz_destroy;
aec_object->iso_to_real_gain = aec_biz_map_iso_to_real_gain;
aec_object->get_version = aec_biz_get_version;
}
//头文件
typedef boolean (* aec_set_parameters_func)(aec_set_parameter_t *param,
aec_output_data_t *output, uint8_t num_of_outputs, void *aec_obj);
typedef boolean (* aec_get_parameters_func)(aec_get_parameter_t *param,
void *aec_obj);
typedef boolean (* aec_process_func)(stats_t *stats, void *aec_obj,
aec_output_data_t *output, uint8_t num_of_ouputs);
typedef void (* aec_callback_func)(aec_output_data_t *output, void *port);
typedef void *(* aec_init_func)(void *aec_lib);
typedef void (* aec_deinit_func)(void *aec);
typedef float (* aec_iso_to_real_gain)(void *aec_obj, uint32_t iso,
uint8_t camera_id);
typedef boolean (* aec_get_version)(void *aec_obj, Q3a_version_t *version,
uint8_t camera_id);

typedef struct _aec_object {
pthread_mutex_t obj_lock;
void *aec;
aec_set_parameters_func set_parameters;
aec_get_parameters_func get_parameters;
aec_process_func process;
aec_init_func init;
aec_deinit_func deinit;
aec_output_data_t output;
aec_iso_to_real_gain iso_to_real_gain;
q3a_custom_data_t aec_custom_param;
aec_get_version get_version;
} aec_object_t;

注释

由于变量可能到处被定义和引用,当它被引用的次数很多时,就很难找到这个变量的含义。可以变量值前面需要加上@,这样搜索变量的含义很快。
在高通代码中搜索某个变量的意义的时候,也可以使用这个方法进行查找。
下面是注释范例:

/*===========================================================================
* FUNCTION : set_parameters
*
* DESCRIPTION: set camera parameters
*
* PARAMETERS :
* @device : ptr to camera device struct
* @parms : string of packed parameters
*
* RETURN : int32_t type of status
* NO_ERROR -- success
* none-zero failure code
*==========================================================================*/

能力集的使用

高通很多部分用到能力集,当时一直觉得这个一个多余的操作。后来有了各种各样的设备之后才知道了能力集的好处。

比如说不同的sensor,你会对每个sensor都写一套代码么?每次都在代码中加sensor型号的判断?不说代码复杂,但是肯定很乱。

如果每个sensor都有自己的能力集之后,代码中只需要根据能力集的配置进行判断,就屏蔽了对sensor型号的判断,即使是新增一个sensor型号,也只需要多配置一组能力集,十分方便。继续推广开来,视频流也有自己的能力集(如分辨率,格式等),每个设备也有自己的能力集(如不同的镜头,sensor型号,各种功能的配置),这样就更加容易实现各种各样设备的管理。

能力集中可能会用到多组配置,比如多种分辨率有不同的配置。这个时候可以在结构体里面定义数组,也可以定义指针。数组会提前分配内存,可能会分配大了,占用空间,指针的话分配的内存可控。

高通的能力集也经历了几个阶段:8056的老代码是把能力集写到代码里面,编译成动态库,进行调用的。后来变成了利用xml进行配置,在设备中读取进行配置。再接下来,是在本地将xml编译成bin文件,在设备中进行读取,减少xml解码的时间,提高效率。

typedef struct power_setting_t
{
int seq_val;
int delay;
};
typedef struct power_setting_array
{
power_setting_t power_setting_a[10];
power_setting_t *power_setting_b;
int num;
};
static power_setting_t test_b[] = {
{
.seq_val = 1,
.delay = 1,
},
{
.seq_val = 2,
.delay = 2,
}};
static power_setting_array test = {
//结构体有两种非顺序的赋值方法,冒号和等号都可以
.power_setting_a = {
{
seq_val : 1,
delay : 1,
},
{
.seq_val = 2,
.delay = 2,
}},
.power_setting_b = test_b,
.num = sizeof(test_b) / sizeof(test_b[0]),
};

回调函数的注册和使用