Custom port A9G module: help wanted

C programming, build, interpreter/VM.
Target audience: MicroPython Developers.
pulkin
Posts: 25
Joined: Tue Feb 19, 2019 10:22 pm

Custom port A9G module: help wanted

Post by pulkin » Tue Feb 19, 2019 10:55 pm

Hi community,

I am porting micropython to the A9 GSM module (see also: A9G, RDA8955). It usually comes as a part of the board with a charge controller, external antennae, etc.: a very interesting piece of hardware overall from ESP manufacturers. The ongoing work is here: https://github.com/pulkin/micropython

I reserve this thread for my questions and your help with this implementation.

My first question is:

I am implementing a simple callback enabling updates of the GSM signal level in python. This is done through events in the original SDK, something like this (sorry for indents: have no idea how to post it here properly):

case API_EVENT_ID_SIGNAL_QUALITY:
mp_warning("API_EVENT_ID_SIGNAL_QUALITY");
notify_signal(pEvent);
break;

The actual python interface looks like this:

void notify_signal(API_Event_t* event) {
if (signal_callback == mp_const_none) {
return;
}

if (!MP_OBJ_IS_FUN(signal_callback)) {
mp_warning("The GSM signal callback is not a function");
return;
}

nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_warning("Calling ...");
mp_obj_t ret = mp_call_function_0(signal_callback);
nlr_pop();
} else {
signal_callback = mp_const_none;
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
}
}

The problem is that this code ends up in nlr_jump_fail when the actual event occurs. The callback is a simple "print" function but the last thing printed is "Calling ...". The question is: how to implement this callback properly?

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

Re: Custom port A9G module: help wanted

Post by jickster » Wed Feb 20, 2019 3:02 am

Remind me


Sent from my iPhone using Tapatalk Pro

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

Re: Custom port A9G module: help wanted

Post by jickster » Wed Feb 20, 2019 4:34 pm

Short version: you’re not sending a micropython object ie it’s more complicated.

Long version: forthcoming.


Sent from my iPhone using Tapatalk Pro

pulkin
Posts: 25
Joined: Tue Feb 19, 2019 10:22 pm

Re: Custom port A9G module: help wanted

Post by pulkin » Wed Feb 20, 2019 8:34 pm

Ok, I looked into ESP pin callback implementation and found that these callbacks belong to root pointers. Am I on the right way?

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

Re: Custom port A9G module: help wanted

Post by jickster » Thu Feb 21, 2019 2:27 pm

pulkin wrote:Ok, I looked into ESP pin callback implementation and found that these callbacks belong to root pointers. Am I on the right way?
Root pointers are not why you’re failing here.

Look at the implementation of mp_call_function_0() and you’ll see your problem: you’re not passing the type it expects.


Sent from my iPhone using Tapatalk Pro

pulkin
Posts: 25
Joined: Tue Feb 19, 2019 10:22 pm

Re: Custom port A9G module: help wanted

Post by pulkin » Thu Feb 21, 2019 5:21 pm

What exactly do you mean?

Code: Select all

mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
    // TODO improve this: fun object can specify its type and we parse here the arguments,
    // passing to the function arrays of fixed and keyword arguments

    DEBUG_OP_printf("calling function %p(n_args=" UINT_FMT ", n_kw=" UINT_FMT ", args=%p)\n", fun_in, n_args, n_kw, args);

    // get the type
    mp_obj_type_t *type = mp_obj_get_type(fun_in);

    // do the call
    if (type->call != NULL) {
        return type->call(fun_in, n_args, n_kw, args);
    }

    if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
        mp_raise_TypeError("object not callable");
    } else {
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
            "'%s' object isn't callable", mp_obj_get_type_str(fun_in)));
    }
}
I doubt it is a type issue since I am sometimes able to invoke the callback successfully. For example, if I am doing it in the same "thread":

Code: Select all

>>> f = lambda: print("hi")
>>> f()
hi
>>> set_callback(f)
>>> test_callback()
hi
>>>

pulkin
Posts: 25
Joined: Tue Feb 19, 2019 10:22 pm

Re: Custom port A9G module: help wanted

Post by pulkin » Thu Feb 21, 2019 9:07 pm

Ok, I think I pinned the error down to mp_stack_check using a sh*t-and-sticks debugger:

Code: Select all

void mp_stack_check(void) {
    mp_warning("mp_stack_check");
    if (mp_stack_usage() >= MP_STATE_THREAD(stack_limit)) {
        mp_warning("  raising: %u >= %u", mp_stack_usage(), MP_STATE_THREAD(stack_limit));
        mp_raise_recursion_depth();
    }
}
Which fails with

Code: Select all

Warning: mp_stack_check
Warning:   raising: 4294934832 >= 31744
Warning: mp_stack_check
Warning:   raising: 4294934816 >= 31744
It seems like I have to set stack_top properly once micropython code runs in a new "thread"(task) or something.

pulkin
Posts: 25
Joined: Tue Feb 19, 2019 10:22 pm

Re: Custom port A9G module: help wanted

Post by pulkin » Fri Feb 22, 2019 12:57 am

I resolved it, sort of. But I still need feedback. What I did is I created a timer sending recurring event to the REPL task (i.e. the one handling intialization and UART input). mp_handle_pending is invoked in the task. mp_sched_schedule is used to run callbacks. Is it OK?

pulkin
Posts: 25
Joined: Tue Feb 19, 2019 10:22 pm

Re: Custom port A9G module: help wanted

Post by pulkin » Sat Feb 23, 2019 8:47 pm

In the end, the problem looks for me as following: I do not have access to interrupts in the event-driven SDK. If I want to process interrupts I either wait for micropython code to finish or do that in a different task having its own stack. As a result, the code fails at stack check. It is possible to turn it off by setting MICROPY_STACK_CHECK but I am wondering for more conventional ways of implementing this.

pfalcon
Posts: 1155
Joined: Fri Feb 28, 2014 2:05 pm

Re: Custom port A9G module: help wanted

Post by pfalcon » Fri Mar 08, 2019 10:14 pm

more conventional ways of implementing this
There's a more conventional way to do it, it's: avoid callbacks at all costs. Callbacks are available in a small part of MicroPython API dedicated to baremetal to show that MicroPython can do anything. But beyond that "yes, we can", callbacks don't scale, especially to (RT)OS environments, as your example shows, and PITA for users to use (they never get how to use them correctly). Avoid callbacks at all costs. Unless you know better (but then you don't ask "why it doesn't work").
Awesome MicroPython list
Pycopy - A better MicroPython https://github.com/pfalcon/micropython
MicroPython standard library for all ports and forks - https://github.com/pfalcon/micropython-lib
More up to date docs - http://pycopy.readthedocs.io/

Post Reply