micropython用c添加接口——添加type

前面讲的如何向micropython添加一个module并在module下面添加function。可以看出来很多的操作步骤都是有类比性的。这一篇就重点讲如何添加type,以及给type 类添加function功能。聪明的小伙伴已经可以猜到和之前添加module差不多。但是除了差不多还是有一些区别的,这也是这篇文章的重点。

先看下之前介绍框架的时候的一张图:

micropython用c添加接口——添加type

你首先要把这个框架图映在脑子里,这样等一会儿你看代码的时候就不会晕头转向。抓住核心再深入细节才是完美的思路。添加type相对来说会比添加module复杂一些,所以代码量也会多一些。好,下面正式进入主题:

第一步:从最简单开始,先添加一个空的type类型到我们之前的modtest中。

在ports/esp32下面新建一个文件:modtest_math.c

打开文件,添加如下代码:

#include "stdint.h"
#include "stdio.h"

#include "py/obj.h"
#include "py/runtime.h"

//定义type的locals_dict_type
STATIC const mp_rom_map_elem_t math_locals_dict_table[] = {
};
//这个定义字典的宏定义
STATIC MP_DEFINE_CONST_DICT(math_locals_dict, math_locals_dict_table);

//定义一个mp_obj_type_t 类型的结构体。注意这里和定义module使用的类型是不一样的
const mp_obj_type_t modtest_math_type = {
    .base={ &mp_type_type }, 
    .name = MP_QSTR_math,           //type 类的name属性是放在这里定义的,而不是放在DICT中
    .locals_dict = (mp_obj_dict_t*)&math_locals_dict,   //注册math_locals_dict
};

看上面的代码结构和定义一个module是不是类似的,只是需要注意的地方就是,这里定义type就要用mp_obj_type_t 该类型,modtest_math_type 就是用来向module注册的接口。再mp_obj_type_t 中的成员和mp_obj_module_t是不一样的。在 math_locals_dict_table里面我们什么都没添加,后面我们会添加function就是添加到这里。我们一步步来,先确保添加type类型是OK的。

第二步:我们新建的c文件那肯定是要添加到makefile文件里面,要参与编译啊

打开Makefile文件,找到我们之前添加modtest.c的地方,排上队把新建的modtest_math.c按照一样的格式写在后面:

SRC_C = \
	main.c \
        …………
	modtest.c\
	modtest_math.c\
	$(SRC_MOD)

第三步:把定义的modtest_math_type  注册到modtest里,打开modtest.c添加如下代码:

extern const mp_obj_type_t modtest_math_type;  //引用外部定义
STATIC const mp_rom_map_elem_t modtest_globals_table[] = {
    {MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_modtest)},
    {MP_OBJ_NEW_QSTR(MP_QSTR_test0), MP_ROM_PTR(&modtest_obj_test0)},
    {MP_OBJ_NEW_QSTR(MP_QSTR_test1), MP_ROM_PTR(&modtest_obj_test1)},
    {MP_OBJ_NEW_QSTR(MP_QSTR_math), MP_ROM_PTR(&modtest_math_type)}, //这个是我们新添加的,把modtest_math_type 注册进来
};

添加完毕以后,编译烧录再测试,结果如下就证明添加好了:

micropython用c添加接口——添加type

从测试结果看我们名为math的type已经添加成功了,用type() 检查下类型,没错,是class type类的。

第四步:在type中添加无参数的function

直接上代码:

//定义无参数函数
STATIC mp_obj_t math_nothing()
{
    printf("This is a function in class type and no parameter\n");
    return mp_const_none;
}
//使用函数参数使用对应宏定义
STATIC MP_DEFINE_CONST_FUN_OBJ_0(math_nothing_obj,math_nothing);

STATIC const mp_rom_map_elem_t math_locals_dict_table[] = {
    { MP_ROM_QSTR(MP_QSTR_nothing), MP_ROM_PTR(&math_nothing_obj) },    //添加的DICT里面去
};

这个步骤没啥可解释的,和module添加无参数的函数是一样的:

编译执行验证结果如下:

micropython用c添加接口——添加type

 

第五步:在type中添加有一个参数的function(注意,关键点来了)

惯性思维让我以为在type中添加带有一个参数的函数会和module一样,折腾了两个小时候才发现这里和module的区别还是很大。你可以自行尝试,我这里只提供正确的思路。

type类型在python中是类,而要操作带参数的函数就需要实例化一个对象出来:比如 mymath=modtest.math()  那么对应到c语言肯定要有一个对应的分配空间创建对象的函数,还有表示对象的结构体。

在modtest_math.c中添加一个math_obj_t 的结构体,用来表示一个math对象的结构:

typedef struct _math_obj_t
{
    mp_obj_base_t base;   //定义的对象结构体要包含该成员
    uint16_t value1;      //下面的成员,根据需要自己添加
    uint16_t value2;
}math_obj_t;

接下来为modtest_matg_type 添加.make_new 属性,以及对应的make new函数:

//make new 穿件一个实例对象的函数
STATIC mp_obj_t modtest_math_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args)
{
    mp_arg_check_num(n_args, n_kw, 0, 0, true);   //检查参数个数
    math_obj_t *self=m_new_obj(math_obj_t);       //创建对象,分配空间
    self->base.type=&modtest_math_type;           //定义对象的类型
    return MP_OBJ_FROM_PTR(self);                 //返回对象的指针
}
const mp_obj_type_t modtest_math_type = {
    .base={ &mp_type_type }, 
    .name = MP_QSTR_math,
    .make_new=modtest_math_make_new,       //这个是我们新添加的make new属性
    .locals_dict = (mp_obj_dict_t*)&math_locals_dict,
};

好了,现在我们的math就可以进行实例化了。看到这里,你是不是以为和“添加有一个参数的function”的标题跑偏了?no,no!前面的实现了,我们才能实现下面的功能。

添加如下代码:

//定义math_add函数
mp_obj_t math_add(mp_obj_t self_in,mp_obj_t data) { 	
    math_obj_t *self=MP_OBJ_TO_PTR(self_in);  //从第一个参数里面取出对象的指针
    self->value1=100;                    
    self->value2=mp_obj_get_int(data);    //从第二个参数里面取出整型数值
	printf("100+%d=\n",self->value2);
	return mp_obj_new_int(self->value1+self->value2);  //返回计算的结果
}
//注意两点,我这里使用的是OBJ_2而不是OBJ_1
STATIC MP_DEFINE_CONST_FUN_OBJ_2(math_add_obj, math_add);

STATIC const mp_rom_map_elem_t math_locals_dict_table[] = {
    { MP_ROM_QSTR(MP_QSTR_nothing), MP_ROM_PTR(&math_nothing_obj) },
    { MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&math_add_obj) },  //把我们定义的function对象添加到DICT中
};

先看运行结果:

micropython用c添加接口——添加type

在python中我们先定义实例化一个对象m=modtest.math(),然后就可以使用传递参数的方法了:m.add(200) 计算结果也正确

那么有没有感觉很奇怪,我们这里m.add(200)只是传递了一个参数进去,但是在代码中我们却使用了MP_DEFINE_CONST_FUN_OBJ_2两个参数的宏。这里也是和定义module的function区别大的地方。在type型class 中传递参数的时候,默认第一个并不是我们在python层面填进去的参数,而是一个实例化对象的指针,第二个参数才是我们传递进去的。

可能有点晕,自己动手写代码操作操作就明白了!!

如还有其他疑问,欢迎加QQ:849664628 探讨

 

 


转载请注明转自电子创客营:micropython用c添加接口——添加type! 了解我们点击这里
喜欢 (5)or分享 (0)
电子创客营
关于作者:
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址