Using the C API?

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
hjf
Posts: 12
Joined: Sat Feb 27, 2016 3:47 am

Using the C API?

Post by hjf » Sat Feb 27, 2016 3:54 am

Could anyone provide me with a small working example of what's discussed here? https://www.kickstarter.com/projects/21 ... sts/679050

Just a simple "Hello World!" function in C that I can call from Python, and the opposite as well.

Thanks!

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

Re: Using the C API?

Post by dhylands » Sat Feb 27, 2016 6:10 am

Here's a simple sample I put on a github branch:
https://github.com/dhylands/micropython ... 0d64ef7172

Here's the output from running it:

Code: Select all

>>> import c_sample
>>> def foo():
...     print('foo called')
... 
>>> c_sample.set_callback(foo)
>>> c_sample.call_callback()
foo called
And all of the peripherals are essentially similar. Look at things like stmhal/modpyb.c, or stmhal/timer.c (which has an example of calling python from C code).

hjf
Posts: 12
Joined: Sat Feb 27, 2016 3:47 am

Re: Using the C API?

Post by hjf » Sat Feb 27, 2016 1:29 pm

Thanks a lot!

hjf
Posts: 12
Joined: Sat Feb 27, 2016 3:47 am

Re: Using the C API?

Post by hjf » Mon Feb 29, 2016 3:37 am

I tried to base on your code to make a small function but I just can't seem to make it work.

I redefined your C function as:

Code: Select all

STATIC mp_obj_t c_sample_call_callback(void) {
    vstr_t vstr;
    vstr_init_fixed_buf(&vstr, 32, "some_string");

    mp_obj_t obj = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
    return mp_call_function_1(MP_STATE_PORT(c_sample_callback_obj),obj);

}
and the Python session looks like:

Code: Select all

MicroPython 84405ef-dirty on 2016-02-29; linux version
Use Ctrl-D to exit, Ctrl-E for paste mode
>>> def a(b):
...     print(b)
...
...
...
>>> import c_sample
>>> c_sample.set_callback(a)
>>> c_sample.call_callback
<function>
What am I doing wrong?

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

Re: Using the C API?

Post by dhylands » Mon Feb 29, 2016 5:11 am

You're missing the parenthesis when you're trying to call the call_callback function. Instead of

Code: Select all

>>> c_sample.call_callback
you should be using

Code: Select all

>>> c_sample.call_callback()

hjf
Posts: 12
Joined: Sat Feb 27, 2016 3:47 am

Re: Using the C API?

Post by hjf » Mon Feb 29, 2016 10:52 am

dhylands wrote:You're missing the parenthesis when you're trying to call the call_callback function
Ah yes. Also known as the "don't try to program when it's 1AM and your eyes can't even focus on the screen"

But now I get this:

Code: Select all

>>> c_sample.call_callback()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError: memory allocation failed, allocating 1 bytes

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

Re: Using the C API?

Post by dhylands » Mon Feb 29, 2016 4:23 pm

You're misuing vstr. In particular, the vstr passed into mp_obj_new_str_from_vstr needs to be heap allocated.

You could use:

Code: Select all

STATIC mp_obj_t c_sample_call_callback(void) {
    mp_obj_t obj = mp_obj_new_str("some_string", strlen("some_string"), false);
    return mp_call_function_1(MP_STATE_PORT(c_sample_callback_obj), obj);
}
You'll need to also add a #include <string.h>. This produces:

Code: Select all

>>> def foo(b):
...     print(b)
... 
>>> import c_sample
>>> c_sample.set_callback(foo)
>>> c_sample.call_callback()
some_string
>>> 
If you wanted ot use a vstr, you'd need to do something like:

Code: Select all

STATIC mp_obj_t c_sample_call_callback(void) {
    vstr_t vstr;
    vstr_init_len(&vstr, strlen("some_string"));
    strcpy(vstr.buf, "some_string");
    mp_obj_t obj = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
    return mp_call_function_1(MP_STATE_PORT(c_sample_callback_obj), obj);
} 
which produces:

Code: Select all

>>> def foo(b):
...     print(b)
... 
>>> import c_sample
>>> c_sample.set_callback(b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'b' is not defined
>>> c_sample.set_callback(foo)
>>> c_sample.call_callback()
b'some_string'
mp_obj_t obj = mp_obj_new_str("some_string", strlen("some_string"), false);

cduran
Posts: 80
Joined: Thu Mar 17, 2016 4:52 pm

Re: Using the C API?

Post by cduran » Tue Jul 12, 2016 8:15 pm

Could I add more C callbacks without modifying mpconfigport.h?

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

Re: Using the C API?

Post by dhylands » Tue Jul 12, 2016 9:25 pm

cduran wrote:Could I add more C callbacks without modifying mpconfigport.h?
You only need to modify mpconfigport.h to add the module. Once the module has been added you can add as many methods to the module that you want by just modifying c_sample.c (or whatever you call your module).

By convention, I probably should have called the source modsample.c.

cduran
Posts: 80
Joined: Thu Mar 17, 2016 4:52 pm

Re: Using the C API?

Post by cduran » Wed Jul 13, 2016 3:27 pm

dhylands wrote:
cduran wrote:Could I add more C callbacks without modifying mpconfigport.h?
You only need to modify mpconfigport.h to add the module. Once the module has been added you can add as many methods to the module that you want by just modifying c_sample.c (or whatever you call your module).

By convention, I probably should have called the source modsample.c.
Wouldn't I also have to add the new callbacks to qstrdefsport.h?

Post Reply