阅读micropyton源码-添加C扩展类模块(4)

阅读micropyton源码-添加C扩展类模块(4)

苏勇,2021年8月


make_new()函数实现的相当于初始化一个类实例的操作。初始化之后,用户就可以使用类实例调用函数执行功能。此处再看一遍实现功能函数的写法。

没有输入参数的pin.on() & pin.off()

在“ports/mimxrt/machine_pin.c”找到machine_pin_off()和machine_pin_on()函数:


// pin.off()
STATIC mp_obj_t machine_pin_off(mp_obj_t self_in) {
    machine_pin_obj_t *self = self_in;
    mp_hal_pin_low(self);
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_off_obj, machine_pin_off);

// pin.on()
STATIC mp_obj_t machine_pin_on(mp_obj_t self_in) {
    machine_pin_obj_t *self = self_in;
    mp_hal_pin_high(self);
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_on_obj, machine_pin_on);

这些功能函数是登记到python中的,并不是直接在某个地方被用户直接调用的,所以,还是要关注一下传参的情况。

以machine_pin_off()为例:

  • 返回值类型为mp_obj_t,如果没啥可返回的,就用“return mp_const_none”
  • 传入的第一个参数self_in,实际上就是make_new()参数清单中的第一个参数,从中可以提取到硬件相关的信息,然后调用SDK的API操作底层硬件。这里可以直接调用API,没必要再调用一次mp_hal_pin_low()或者mp_hal_pin_high()。

实际上,在“ports/mimxrt/mphalport.h”中,mp_hal_pin_low()或者mp_hal_pin_high()的代码如下:

#define mp_hal_pin_high(p) (GPIO_PinWrite(p->gpio, p->pin, 1U))
#define mp_hal_pin_low(p) (GPIO_PinWrite(p->gpio, p->pin, 0U))

有输入参数的pin.init()

在“ports/mimxrt/machine_pin.c”找到machine_pin_init()函数:

// pin.init(mode, pull, [kwargs])
STATIC mp_obj_t machine_pin_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
    return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
}
MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_init);

这个我有点看不懂了,我本来期望第一个参数也是self_in,但这里使用了参数列表的方式传参:n_args是用户传参的参数数量,args是位置参数列表,kw_args是穿好马甲的关键字参数列表。

我在想这里是不是特别为了复用machine_pin_obj_init_helper()函数才写成这个样子。看了rp2的实现,更是乱七八糟,至少mimxrt还是有点规范的,还是参考mimxrt的做法吧。

只要有参数,统一用参数列表的方式传参,就都能cover住。

宏函数“MP_DEFINE_CONST_FUN_OBJ_KW()”中的这个参数“1”,参考在“py/obj.h”中的定义,表示至少有1个参数。

#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}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name}

有返回值的pin.value()

在“ports/mimxrt/machine_pin.c”找到machine_pin_init()函数:

// pin.value([value])
STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) {
    return machine_pin_obj_call(args[0], (n_args - 1), 0, args + 1);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value);

有了在pin.init()上的前车之鉴,这个pin.value()使用位置参数清单保存传入参数,已经见怪不怪了。

这里也是复用了machine_pin_obj_call()函数。

最后使用了“MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN()”宏函数,表示至少有1参数,最多有2个参数?2个参数是什么鬼?

#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}, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, false), .fun.var = fun_name}

返回值的处理,只要返回对象就好,如果是整数,就用宏函数“MP_OBJ_NEW_SMALL_INT()”将整数转成OBJ的形式直接返回就好,这个返回值会直接返回到用户脚本中。

小结

功能函数的写法:无参数、有关键字参数(参数数量大于等于1)、仅有位置参数(参数数量大于1)、有返回值,几种要素都已经展现出来。

下一步,套用这里的模式实现在新平台上的移植,遇到具体问题再参考现有各家的实现。


从早写到晚,真写得块吐了。
END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值