在micropython中,通常使用些宏定义和结构体,没有弄明白这些宏和结构体很难自己写出高质量的模块。比如,怎么传递参数,怎么返回参数,这些宏和结构体大多位于 micropython\py的obj.h文件中。
在micropython的obj.h中有两个非常重要的定义,几乎所有的文件中都能看到。
mp_obj_type_t:
struct _mp_obj_type_t {
mp_obj_base_t base;
qstr name;
mp_print_fun_t print;
mp_make_new_fun_t make_new;
mp_call_fun_t call;
mp_unary_op_fun_t unary_op;
mp_binary_op_fun_t binary_op;
mp_attr_fun_t attr;
mp_subscr_fun_t subscr;
mp_getiter_fun_t getiter;
mp_fun_1_t iternext;
mp_buffer_p_t buffer_p;
const void *protocol;
const void *parent;
struct _mp_obj_dict_t *locals_dict;
};
和mp_obj_t(或者mp_const_obj_t):
typedef void *mp_obj_t;
typedef const void *mp_const_obj_t;
其中mp_obj_t实际就是void指针,void指针是一种无类型指针,用于指向任何类型的数据。在获取void指针所指向的变量值时候,需要先将void指针强制类型转换成和变量名类型想匹配的数据类型指针后再进行操作。
比如下面的函数返回了一个ADC值:
STATIC mp_obj_t adc_read(mp_obj_t self_in) {
pyb_obj_adc_t *self = self_in;
adc_config_channel(&self->handle, self->channel);
uint32_t data = adc_read_channel(&self->handle);
return mp_obj_new_int(data);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
而函数如果需要取到传入的参数,则要使用micropython在obj.c中定义的取值函数,比如:
mp_int_t mp_obj_get_int(mp_const_obj_t arg)
mp_float_t mp_obj_get_float(mp_obj_t arg)
void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag)
micropython中的字典非常重要,这个宏也在obj.h中:
#define MP_DEFINE_CONST_DICT(dict_name, table_name) \
const mp_obj_dict_t dict_name = { \
.base = {&mp_type_dict}, \
.map = { \
.all_keys_are_qstrs = 1, \
.is_fixed = 1, \
.is_ordered = 1, \
.used = MP_ARRAY_SIZE(table_name), \
.alloc = MP_ARRAY_SIZE(table_name), \
.table = (mp_map_elem_t*)(mp_rom_map_elem_t*)table_name, \
}, \
}
至于micropython怎么使用这个DICT里的函数,以pyb_adc为例,要依靠下面的这个mp_obj_type_t的结构体,其中.locals_dict被赋值的正是上面这个dict_name:
const mp_obj_type_t pyb_adc_type = {
{ &mp_type_type },
.name = MP_QSTR_ADC,
.print = adc_print,
.make_new = adc_make_new,
.locals_dict = (mp_obj_dict_t*)&adc_locals_dict,
};
这个结构体会出现在对应的adc.h文件中,从而可以在modpyb.c中被引用,并最终编译后被micropython使用:
extern const mp_obj_type_t pyb_adc_type;
以下是adc.c中进一步对应的实例:
STATIC const mp_rom_map_elem_t adc_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&adc_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_read_timed), MP_ROM_PTR(&adc_read_timed_obj) },
};
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
从相关的宏中可以看到,dict名为adc_local_dict,table名为adc_local_dict_table。adc_local_dict_table是按mp_rom_map_elem_t的结构体来组织的,其主要内容就是这个函数的地址。
这个MP_ROM_PTR中的adc_read_obj对应的定义也在adc.c的文件中:
STATIC mp_obj_t adc_read(mp_obj_t self_in) {
pyb_obj_adc_t *self = self_in;
adc_config_channel(&self->handle, self->channel);
uint32_t data = adc_read_channel(&self->handle);
return mp_obj_new_int(data);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
通过MP_DEFINE_CONST_FUN_OBJ_1将adc_read_obj和adc_read这个实体的读取adc值的函数对应起来。这个MP_DEFINE_CONST_FUN_OBJ_1的宏在obj.h中可以看到:
#define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) \
const mp_obj_fun_builtin_fixed_t obj_name = \
{{&mp_type_fun_builtin_0}, .fun._0 = fun_name}
#define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) \
const mp_obj_fun_builtin_fixed_t obj_name = \
{{&mp_type_fun_builtin_1}, .fun._1 = fun_name}
#define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) \
const mp_obj_fun_builtin_fixed_t obj_name = \
{{&mp_type_fun_builtin_2}, .fun._2 = fun_name}
#define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) \
const mp_obj_fun_builtin_fixed_t obj_name = \
{{&mp_type_fun_builtin_3}, .fun._3 = fun_name}
#define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) \
const mp_obj_fun_builtin_var_t obj_name = \
{{&mp_type_fun_builtin_var}, false, n_args_min, MP_OBJ_FUN_ARGS_MAX, .fun.var = fun_name}
#define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) \
const mp_obj_fun_builtin_var_t obj_name = \
{{&mp_type_fun_builtin_var}, false, n_args_min, n_args_max, .fun.var = fun_name}
#define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) \
const mp_obj_fun_builtin_var_t obj_name = \
{{&mp_type_fun_builtin_var}, true, n_args_min, MP_OBJ_FUN_ARGS_MAX, .fun.kw = fun_name}
以上内容中包括两个重要的结构体:
typedef struct _mp_obj_fun_builtin_fixed_t {
mp_obj_base_t base;
union {
mp_fun_0_t _0;
mp_fun_1_t _1;
mp_fun_2_t _2;
mp_fun_3_t _3;
} fun;
} mp_obj_fun_builtin_fixed_t;
和
typedef struct _mp_obj_fun_builtin_var_t {
mp_obj_base_t base;
bool is_kw : 1;
mp_uint_t n_args_min : 15; // inclusive
mp_uint_t n_args_max : 16; // inclusive
union {
mp_fun_var_t var;
mp_fun_kw_t kw;
} fun;
} mp_obj_fun_builtin_var_t;
这里用到的一些函数的定义如下,可以看到MP_DEFINE_CONST_FUN_OBJ_1这些宏后面的数字对应是几个参数:
typedef mp_obj_t (*mp_fun_0_t)(void);
typedef mp_obj_t (*mp_fun_1_t)(mp_obj_t);
typedef mp_obj_t (*mp_fun_2_t)(mp_obj_t, mp_obj_t);
typedef mp_obj_t (*mp_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t);
typedef mp_obj_t (*mp_fun_var_t)(size_t n, const mp_obj_t *);
typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *);
以下是一些例子:
modmath.phase(z)中有一个参数z_obj:
STATIC mp_obj_t mp_cmath_phase(mp_obj_t z_obj) {
mp_float_t real, imag;
mp_obj_get_complex(z_obj, &real, &imag);
return mp_obj_new_float(MICROPY_FLOAT_C_FUN(atan2)(imag, real));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_phase_obj, mp_cmath_phase);
lcd.fill(colour)中有两个参数self_in和col_in:
STATIC mp_obj_t pyb_lcd_fill(mp_obj_t self_in, mp_obj_t col_in) {
pyb_lcd_obj_t *self = self_in;
int col = mp_obj_get_int(col_in);
if (col) {
col = 0xff;
}
memset(self->pix_buf, col, LCD_PIX_BUF_BYTE_SIZE);
memset(self->pix_buf2, col, LCD_PIX_BUF_BYTE_SIZE);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_lcd_fill_obj, pyb_lcd_fill);
lcd.get(x,y)中有三个参数elf_in、x_in和y_in:
STATIC mp_obj_t pyb_lcd_get(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) {
pyb_lcd_obj_t *self = self_in;
int x = mp_obj_get_int(x_in);
int y = mp_obj_get_int(y_in);
if (0 <= x && x <= 127 && 0 <= y && y <= 31) {
uint byte_pos = x + 128 * ((uint)y >> 3);
if (self->pix_buf[byte_pos] & (1 << (y & 7))) {
return mp_obj_new_int(1);
}
}
return mp_obj_new_int(0);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_lcd_get_obj, pyb_lcd_get);
dac.init()中有n_args,*args和*kw_args:
STATIC mp_obj_t pyb_dac_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
return pyb_dac_init_helper(args[0], n_args - 1, args + 1, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_init_obj, 1, pyb_dac_init);