当前位置:网站首页>Read the source code of micropyton - add the C extension class module (2)

Read the source code of micropyton - add the C extension class module (2)

2022-06-10 21:05:00 suyong_ yq

read micropyton Source code - add to C Extension class module (2)

Su Yong ,2021 year 8 month

have a look machine_pin_type Definition of instance

go back to ports/mimxrt/machine_pin.c file , Same as machine_pin_type There are also “machine_pin_af_type”, stay “pin.h” and “ports/mimxrt/boards/mimxrt_prefix.c” It is mentioned in the document , About the reuse of specified pin functions , It also seems to be defined as an instance object , But it is not registered in any module , For the time being , After reading machine_pin_type Then come back and see .

as for “machine_pin_irq_methods”, Still defining machine_pin_type Is called in the method to which the , I'll see it later .

Told the side story , Finally, I can calm down and pay attention to machine_pin_type 了 .

const mp_obj_type_t machine_pin_type = {
    
    {
    &mp_type_type},
    .name = MP_QSTR_Pin,
    .print = machine_pin_obj_print,
    .call = machine_pin_obj_call,
    .make_new = mp_pin_make_new,
    .locals_dict = (mp_obj_dict_t *)&machine_pin_locals_dict,
};

Whole machine_pin.c Just to fill this one mp_obj_type_t Examples of structures of type , What's used here is “ Hard callback ” The encoding mode of . About “mp_obj_type_t” The definition of , For details, see “py/obj.h” file , Only the necessary fields are explained here .

  • “&mp_type_type” Specify that the base class of this module is a type object , Directly inherits some types (type) Object method .“mp_type_type” stay dynruntime.h The document defines , Same as mp_type_type There are also mp_type_str、mp_type_tuple、mp_type_list etc. .

  • “.name” The name of this module is registered in , stay python In the implementation of , Are indexed by name strings , Keyword strings are all in qstr type ,qstr The string of type is used directly “MP_QSTR_” Prefix , And don't use double quotation marks . This is during compilation , Will compile the host python Scripts automatically extract these qstr Actual string for , This operation is similar to c Preprocessing in the compiler tool chain .

  • “.print” Specified function , It is when the user is python Call in print(Pin) Function time , take Pin The instantiated object of is printed as a string .

machine_pin Yes print The implementation of the function is as follows , Print “machine_pin_obj_t” Structure type “name” Field string .

STATIC void machine_pin_obj_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) {
    
    (void)kind;
    const machine_pin_obj_t *self = MP_OBJ_TO_PTR(o);
    mp_printf(print, "Pin(%s)", qstr_str(self->name));
}

“machine_pin_obj_t” The structure type is in “pin.h” Defined in the file , But I think it can also be placed directly in “machine_pin.h” In file . stay mimxrt In the implementation of ,machine_pin_type and machine_pin_af_type All belong to “pin.h” in . As for this “name” When was the field filled in , I guess it is. new Filled in when , Let's wait and see .“mp_print_t” Is the printed object , It can be an interactive terminal , It can also be log file .

  • “.call” Specified function , The corresponding is Python An instance method of a very special class in , namely __call__(). The function of this method is similar to overloading in a class () Operator , So that the class instance object can call ordinary functions , With “ Object name ()” In the form of . To be frank , The name of the instance object itself is also regarded as a function name .machine_pin Yes call The implementation of the function is as follows :
STATIC mp_obj_t machine_pin_obj_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
    
    mp_arg_check_num(n_args, n_kw, 0, 1, false);
    machine_pin_obj_t *self = self_in;

    if (n_args == 0) {
    
        return MP_OBJ_NEW_SMALL_INT(mp_hal_pin_read(self));
    } else {
    
        mp_hal_pin_write(self, mp_obj_is_true(args[0]));
        return mp_const_none;
    }
}

Combined with the implementation example here call() Usage of attribute function :

pin1 = Pin() #  Instantiate a Pin The object of pin1
print(pin1()) #  If the number of parameters is 0 individual , Then return to mp_hal_pin_read() Function to read the pin value 
pin1(0) # If the parameter is 1 individual , Then the first parameter passed in args[0] As mp_hal_pin_write() The parameters of the function , The write pin specifies the level value 

See :Python call() Method ( Detailed Edition )

  • “.make_new” Specified function , Is the operation process of instantiating a class object . This new The function will “ Out of thin air ”, stay gc Dynamically apply for a piece of memory in the managed memory area , Fill in the necessary attribute information , Then the handle of this memory ( The pointer ) Back to the caller . The corresponding... Will be described in detail below “mp_pin_make_new()” Implementation of function , The parameter transfer process implemented by this function is quite interesting , You can specify objects in different numbering ways , There will be a special space for a detailed introduction below .

Add a sentence , If you follow a seemingly uniform naming convention , there “mp_pin_make_new()” Function names should be used like other attribute functions “machine_pin_obj” Prefix , be called “machine_pin_obj_make_new”

  • “.locals_dict” Is a list of local keywords contained in this class and their corresponding functions ( Constant ? function ?). stay python There is a built-in function in locals(),locals() The function returns all local variables in the current position as dictionary type . Guess what's going on here “locals_dict” Is to provide a returnable Dictionary , Also used as a module internal “.” The property and method resources that the operator continues to access .

See :Python locals() function

machine_pin Yes locals_dict The implementation is as follows :

STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
    
    // instance methods
    {
     MP_ROM_QSTR(MP_QSTR_off),     MP_ROM_PTR(&machine_pin_off_obj) },
    {
     MP_ROM_QSTR(MP_QSTR_on),      MP_ROM_PTR(&machine_pin_on_obj) },
    {
     MP_ROM_QSTR(MP_QSTR_low),     MP_ROM_PTR(&machine_pin_off_obj) },
    {
     MP_ROM_QSTR(MP_QSTR_high),    MP_ROM_PTR(&machine_pin_on_obj) },
    {
     MP_ROM_QSTR(MP_QSTR_value),   MP_ROM_PTR(&machine_pin_value_obj) },
    {
     MP_ROM_QSTR(MP_QSTR_init),    MP_ROM_PTR(&machine_pin_init_obj) },
    {
     MP_ROM_QSTR(MP_QSTR_irq),     MP_ROM_PTR(&machine_pin_irq_obj) },
    // class attributes
    {
     MP_ROM_QSTR(MP_QSTR_board),   MP_ROM_PTR(&machine_pin_board_pins_obj_type) },
    {
     MP_ROM_QSTR(MP_QSTR_cpu),     MP_ROM_PTR(&machine_pin_cpu_pins_obj_type) },
    // class constants
    {
     MP_ROM_QSTR(MP_QSTR_IN),      MP_ROM_INT(PIN_MODE_IN) },
    {
     MP_ROM_QSTR(MP_QSTR_OUT),     MP_ROM_INT(PIN_MODE_OUT) },
    {
     MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(PIN_MODE_OPEN_DRAIN) },

    {
     MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(PIN_PULL_UP_100K) },
    {
     MP_ROM_QSTR(MP_QSTR_PULL_UP_47K), MP_ROM_INT(PIN_PULL_UP_47K) },
    {
     MP_ROM_QSTR(MP_QSTR_PULL_UP_22K), MP_ROM_INT(PIN_PULL_UP_22K) },
    {
     MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(PIN_PULL_DOWN_100K) },
    {
     MP_ROM_QSTR(MP_QSTR_PULL_HOLD), MP_ROM_INT(PIN_PULL_HOLD) },

    {
     MP_ROM_QSTR(MP_QSTR_DRIVER_OFF), MP_ROM_INT(PIN_DRIVE_OFF) },
    {
     MP_ROM_QSTR(MP_QSTR_POWER_0),    MP_ROM_INT(PIN_DRIVE_POWER_0) }, // R0 (150 Ohm @3.3V / 260 Ohm @ 1.8V)
    {
     MP_ROM_QSTR(MP_QSTR_POWER_1),    MP_ROM_INT(PIN_DRIVE_POWER_1) }, // R0/2
    {
     MP_ROM_QSTR(MP_QSTR_POWER_2),    MP_ROM_INT(PIN_DRIVE_POWER_2) }, // R0/3
    {
     MP_ROM_QSTR(MP_QSTR_POWER_3),    MP_ROM_INT(PIN_DRIVE_POWER_3) }, // R0/4
    {
     MP_ROM_QSTR(MP_QSTR_POWER_4),    MP_ROM_INT(PIN_DRIVE_POWER_4) }, // R0/5
    {
     MP_ROM_QSTR(MP_QSTR_POWER_5),    MP_ROM_INT(PIN_DRIVE_POWER_5) }, // R0/6
    {
     MP_ROM_QSTR(MP_QSTR_POWER_6),    MP_ROM_INT(PIN_DRIVE_POWER_6) }, // R0/7

    {
     MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(1) },
    {
     MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(2) },

“mp_rom_map_elem_t” As the name suggests, it is stored in rom Medium map Element type , Contains a number of “ Key value pair ”, On the left for qstr Keyword string of type , The right corresponds to the resource . for example :“MP_QSTR_off” The corresponding is “off” Keywords and functions “machine_pin_off_obj”,“MP_ROM_PTR()” The macro specifically specifies that this is a “PTR” The pointer ;“MP_QSTR_IN” The corresponding is “IN” Key words and “PIN_MODE_IN” Constant ,“MP_ROM_INT()” The macro specifically specifies that this is a “INT” Integers ,“PIN_MODE_INT” The value of is also in “pin.h” Defined in the file .

In particular

stay machine_pin.c Some macro operations are used in the file , Encapsulate a function or an array into an object . Bear in mind , stay python in , Everything is the object , function 、 Array 、 Variables and even constants .

As small as a pointer 、 Constant :

MP_ROM_PTR(&machine_pin_off_obj)
MP_ROM_INT(1)

As big as a function 、 Array :

MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_off_obj, machine_pin_off);
MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_init);
MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);

Their implementation code is in “py/obj.h” In file , It actually defines a new variable that references the current resource :

#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_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}
...

#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, \ }, \ }

As for “mp_type_fun_builtin_1” The definition of , be located “py/objfun.c” In file , Is a constant structure , Not a type :

STATIC mp_obj_t fun_builtin_1_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
    
    assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_1));
    mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);
    mp_arg_check_num(n_args, n_kw, 1, 1, false);
    return self->fun._1(args[0]);
}

const mp_obj_type_t mp_type_fun_builtin_1 = {
    
    {
     &mp_type_type },
    .flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_BUILTIN_FUN,
    .name = MP_QSTR_function,
    .call = fun_builtin_1_call,
    .unary_op = mp_generic_unary_op,
};

“mp_type_fun_builtin_1” Of “.call” Point to “fun_builtin_1_call()” function , From the implementation code of this function, we can see , Among them through “mp_arg_check_num()” The function checks the arguments , Valid incoming parameters are only 1 individual . After through “self->fun._1()” Function execution MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) Carry out the fun_name, and obj_name It's here “self”.

Similarly , stay “fun_builtin_2_call()” Function , The valid parameters are also filtered as 2 individual ,“self->fun._2()” The passed in arguments to the function are two ,args[0] and args[1].

as for func._1 and func._2, And the function pointers of variable parameters or keyword parameters that you may often see later var and kw, In fact, they are all function pointers , Defined in the structure as sharing a block of memory union. stay “py/obj.h” There is :

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;
    uint32_t sig; // see MP_OBJ_FUN_MAKE_SIG
    union {
    
        mp_fun_var_t var;
        mp_fun_kw_t kw;
    } fun;
} mp_obj_fun_builtin_var_t;

This section references a lot of code , It's longer , That's it . The next section explains in detail Pin Definition methods of internal variables and member functions in the module .

END

原网站

版权声明
本文为[suyong_ yq]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/161/202206101740014182.html