Calling a python function from C

C programming, build, interpreter/VM.
Target audience: MicroPython Developers.
gshilling
Posts: 1
Joined: Mon Feb 02, 2015 11:32 pm

Calling a python function from C

Post by gshilling » Mon Feb 02, 2015 11:37 pm

I'm working on embedding micro python into another STM32 C application I have. I would like to be able to call functions in a python script file from the C application. Is there a call like PyObject_GetAttrString from CPython to get a pointer to a function that could then be feed into mp_call_function_n_kw?

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Calling a python function from C

Post by dhylands » Tue Feb 03, 2015 2:28 am

Here's an example of calling a python function from C:
https://github.com/micropython/micropyt ... pin.c#L118

If you search for mp_call_function in the stmhal directory you'll see several other examples.

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Post by Damien » Tue Feb 03, 2015 6:31 pm

You might want to try mp_load_global to get a function (or other object) defined by a script.

Tetraeder
Posts: 53
Joined: Thu Mar 05, 2015 1:12 pm
Location: Germany

Re: Calling a python function from C

Post by Tetraeder » Tue Feb 07, 2017 1:59 pm

I have a similar question to the thread topic:
I create for pyboard the frozen script -> own.py

Code: Select all

def test():
	print('hello test')
I created in stmhal the folder "scripts" and define in Makefile the FROZEN_DIR. Copied the own.py script in folder scripts.
compile-> repl -> works, with

Code: Select all

>>> import own  
>>> own.test()
hello test
>>>
but how can I call this function for example in main.c by "soft reset".
I tried:

Code: Select all

mp_call_function_0(MP_STATE_PORT(own_test))
but no output via repl.
Maybe I don't understand the function :?:

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Calling a python function from C

Post by dhylands » Tue Feb 07, 2017 5:33 pm

The real trick is that you need to register the function from python first so that C can get a pointer to the function.

Otherwise you need to import the module, and then dig the function out of the module, which is doable, just a bunch more code.

You could also do the equivalent to the do_str function in unix/main.c:
https://github.com/micropython/micropyt ... #L287-L290
and call:

Code: Select all

do_str("import own\nown.test()")
Disclaimer: I didn't actually test that.

boot.py and main.py both run as part of a soft-reset.

You need to ensure that you're calling it at the right place in main.c.
boot.py is run before USB is initialized. main.py is run after USB is initialized.

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: Calling a python function from C

Post by jickster » Fri Oct 20, 2017 3:04 pm

dhylands wrote:
Tue Feb 03, 2015 2:28 am
Here's an example of calling a python function from C:
https://github.com/micropython/micropyt ... pin.c#L118

If you search for mp_call_function in the stmhal directory you'll see several other examples.
The link is dead. Please post another one showing how to call Python from C.

User avatar
benalb
Posts: 25
Joined: Fri May 19, 2017 1:23 pm

Re: Calling a python function from C

Post by benalb » Fri Oct 20, 2017 5:23 pm

[/quote]

The link is dead. Please post another one showing how to call Python from C.
[/quote]

I think this is the right link, with the changes in 1.9 tree:

https://github.com/micropython/micropyt ... pin.c#L118

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: Calling a python function from C

Post by jickster » Thu Dec 14, 2017 4:45 pm

dhylands wrote:
Tue Feb 07, 2017 5:33 pm
The real trick is that you need to register the function from python first so that C can get a pointer to the function.

Otherwise you need to import the module, and then dig the function out of the module, which is doable, just a bunch more code.

You could also do the equivalent to the do_str function in unix/main.c:
https://github.com/micropython/micropyt ... #L287-L290
and call:

Code: Select all

do_str("import own\nown.test()")
Disclaimer: I didn't actually test that.

boot.py and main.py both run as part of a soft-reset.

You need to ensure that you're calling it at the right place in main.c.
boot.py is run before USB is initialized. main.py is run after USB is initialized.
How would I call gc_disable() from C?

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Calling a python function from C

Post by dhylands » Mon Dec 18, 2017 8:30 pm

An updated link to the pin.c file (which only moved by a single line) is:
https://github.com/micropython/micropyt ... pin.c#L119

Are you referring to this gc_disable function?
https://github.com/micropython/micropyt ... odgc.c#L45
which is what gets called when you do this in MicroPython:

Code: Select all

import gc
gc.disable()
I guess I would ask what is it that you're really trying to achieve?

To call that exact function from C, you need to locate the gc module, and then look up the disable method. The following:

Code: Select all

    mp_obj_t gc_module_obj = mp_module_get(MP_QSTR_gc);
    if (gc_module_obj) {
      mp_obj_t gc_disable_fn = mp_load_attr(gc_module_obj, MP_QSTR_disable);
      if (gc_disable_fn) {
        mp_call_function_0(gc_disable_fn);
      }
    }
worked for me.

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: Calling a python function from C

Post by jickster » Sat Mar 03, 2018 11:59 pm

dhylands wrote:
Mon Dec 18, 2017 8:30 pm
An updated link to the pin.c file (which only moved by a single line) is:
https://github.com/micropython/micropyt ... pin.c#L119

Are you referring to this gc_disable function?
https://github.com/micropython/micropyt ... odgc.c#L45
which is what gets called when you do this in MicroPython:

Code: Select all

import gc
gc.disable()
I guess I would ask what is it that you're really trying to achieve?

To call that exact function from C, you need to locate the gc module, and then look up the disable method. The following:

Code: Select all

    mp_obj_t gc_module_obj = mp_module_get(MP_QSTR_gc);
    if (gc_module_obj) {
      mp_obj_t gc_disable_fn = mp_load_attr(gc_module_obj, MP_QSTR_disable);
      if (gc_disable_fn) {
        mp_call_function_0(gc_disable_fn);
      }
    }
worked for me.
I want to copy mp_obj_list_t. I know how to do it the long-way: use mp_map_lookup on mp_type_list.locals_dict and call MP_QSTR_copy. Is there a more direct way or do I have to make my own?
I followed through the execution path of mp_module_get(MP_QSTR_list) and it doesn't recurse into the builtins.

The list_copy function and struct are both static so I can't directly call them.

list_copy_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_type_list.locals_dict), MP_OBJ_NEW_QSTR(MP_QSTR_copy));
list_copy_obj->base.type->call(list_copy_obj, 1, 0, & self_can_msg->list_small_int);

Post Reply