Exemplo n.º 1
0
    def build_callbackcode(self):
        func = self.typedef.type.type
        args = func.args.params
        if len(args) < 1 or hasattr(
                args[0].type.type, 'names') and self.lv_base_obj_pattern.match(
                    args[0].type.type.names[0]):
            raise MissingConversionException(
                "Callback: First argument of callback function must be lv_obj_t"
            )
        func_name = get_arg_name(func.type)
        return_type = type_repr(func.type)
        if not self.lv_callback_return_type_pattern.match(return_type):
            raise MissingConversionException(
                "Callback: Can only handle callbaks that return lv_res_t or void"
            )

        code = ("""
/*
 * Callback function {func_name}
 * {func_prototype}
 */

STATIC {return_type} {func_name}_callback({func_args})
{{
    mp_obj_t args[{num_args}];
    {build_args}
    mp_obj_t action = mp_to_lv_action(args[0]);
    mp_obj_t arg_list = mp_obj_new_list({num_args}, args);
    bool schedule_result = mp_sched_schedule(action, arg_list);
    return{return_value};
}}

""".format(func_prototype=generate_c(func),
           func_name=func_name,
           return_type=return_type,
           func_args=', '.join([
               "%s arg%s" % (type_repr(arg.type), i)
               for i, arg in enumerate(args)
           ]),
           num_args=len(args),
           build_args="\n    ".join([
               self.build_callback_func_arg(arg, i, func)
               for i, arg in enumerate(args)
           ]),
           return_value='' if return_type == 'void' else
           ' schedule_result? LV_RES_OK: LV_RES_INV'))

        # Do this after the previous statement, since that may raise a MissingConversionException,
        # in which case we should *not* register the callback
        def register_callback(arg, index, func, obj_name):
            return """set_action(args[0], args[{i}]);
    {arg} = &{func_name}_callback;""".format(i=index,
                                             arg=generate_c(arg),
                                             func_name=func_name)

        mp_to_lv[func_name] = register_callback
        return code
Exemplo n.º 2
0
 def get_GLOBALS_ASSIGNMENTS(self):
     code = ''
     for name, type in self.parseresult.declarations.items():
         typename = type_repr(type)
         code += f'   PyModule_AddObject(module, "{name}", Struct_fromglobal(&py{typename}_Type, &{type.declname}, sizeof({typename})));\n'
         
     return code
Exemplo n.º 3
0
    def gen_mp_func(self, func, obj_name):
        # print("/*\n{ast}\n*/").format(ast=func)
        args = func.type.args.params
        # Handle the case of a single function argument which is "void"
        if len(args) == 1 and type_repr(args[0].type) == "void":
            param_count = 0
        else:
            param_count = len(args)
        return_type = type_repr(func.type.type)
        if return_type == "void":
            build_result = ""
            build_return_value = "mp_const_none"
        else:
            if not return_type in lv_to_mp:
                self.try_generate_type(return_type)
                if not return_type in lv_to_mp:
                    raise MissingConversionException(
                        "Missing convertion from %s" % return_type)
            build_result = "%s res = " % return_type
            build_return_value = lv_to_mp[return_type](func, obj_name) if callable(lv_to_mp[return_type]) else \
                "%s(res)" % lv_to_mp[return_type]
        return ("""
/*
 * lvgl extension definition for:
 * {print_func}
 */
 
STATIC mp_obj_t mp_{func}(size_t n_args, const mp_obj_t *args)
{{
    {build_args}
    {build_result}{func}({send_args});
    return {build_return_value};
}}

MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_{func}_obj, {count}, {count}, mp_{func});

 
""".format(func=func.name,
           print_func=generate_c(func),
           count=param_count,
           build_args="\n    ".join([
               self.build_mp_func_arg(arg, i, func, obj_name)
               for i, arg in enumerate(args) if arg.name
           ]),
           send_args=", ".join(arg.name for arg in args if arg.name),
           build_result=build_result,
           build_return_value=build_return_value))
Exemplo n.º 4
0
 def deref_typedef(self, typestr):
     '''
     Given a type as string representation (e.g. lv_opa_t), recursively
     dereference it using the typedefs in self.parseresult
     '''
     while True:
         typedef = self.parseresult.typedefs.get(typestr)
         if not typedef or not isinstance(typedef.type.type, c_ast.IdentifierType):
             return typestr
         typestr = type_repr(typedef.type)
Exemplo n.º 5
0
 def build_callback_func_arg(self, arg, index, func):
     arg_type = type_repr(arg.type)
     if not arg_type in lv_to_mp:
         self.bindingsgenerator.try_generate_type(arg_type)
         if not arg_type in lv_to_mp:
             raise MissingConversionException(
                 "Callback: Missing conversion to %s" % arg_type)
     return lv_to_mp[arg_type](arg, index, func, obj_name) if callable(lv_to_mp[arg_type]) else \
         'args[{i}] = {convertor}(arg{i});'.format(
             convertor = lv_to_mp[arg_type],
             i = index)
Exemplo n.º 6
0
 def build_mp_func_arg(self, arg, index, func, obj_name):
     arg_type = type_repr(arg.type)
     if not arg_type in mp_to_lv:
         self.try_generate_type(arg_type)
         if not arg_type in mp_to_lv:
             raise MissingConversionException("Missing conversion to %s" %
                                              arg_type)
     return mp_to_lv[arg_type](arg, index, func, obj_name) if callable(mp_to_lv[arg_type]) else \
         '{var} = {convertor}(args[{i}]);'.format(
             var = generate_c(arg),
             convertor = mp_to_lv[arg_type],
             i = index)
Exemplo n.º 7
0
    def deref_typedef(self, typestr):
        '''
        Given a type as string representation (e.g. lv_opa_t), recursively
        dereference it using the typedefs in self.parseresult
        '''
        while True:
            typedef = self.parseresult.typedefs.get(typestr)
            if typedef:
                if isinstance(typedef.type.type, c_ast.IdentifierType):
                    typestr = type_repr(typedef.type)
                    continue  # Continue dereferencing
                if isinstance(typedef.type.type, c_ast.Enum):
                    return 'int'  # Enum is represented by an int

            return typestr
Exemplo n.º 8
0
    def try_generate_type(self, type):
        #TODO: mp_to_lv and lv_to_mp not global, but class or instance members

        if type in mp_to_lv:
            return True

        orig_type = type
        while type in self.parseresult.typedefs:
            type = type_repr(self.parseresult.typedefs[type].type.type)

        # todo: no need to add to mp_to_lv and vv
        if type in mp_to_lv:
            mp_to_lv[orig_type] = mp_to_lv[type]
            lv_to_mp[orig_type] = lv_to_mp[type]

        return False
Exemplo n.º 9
0
    def build_methodcode(self, method):
        object = self
        
        if isinstance(method, CustomMethod):
            return '' # Custom implementation is in lvglmodule_template.c
    
        
        startCode = f'''
static PyObject*
py{method.decl.name}(pylv_Obj *self, PyObject *args, PyObject *kwds)
{{
    if (check_alive(self)) return NULL;
'''
       
        paramnames = []
        paramctypes = []
        paramfmts = []
        for param in method.decl.type.args.params:
            paramtype = type_repr(param.type)
            paramtype_derefed = self.bindingsgenerator.deref_typedef(paramtype)
            
            # For params, if the param type is e.g. "lv_obj_t*", "const lv_obj_t*" is allowed, too
            # However, we do not add "const lv_obj_t*" to the TYPECONV dict, since "const lv_obj_t*" would not be a valid return type
            
            try:
                fmt, ctype = self.TYPECONV_PARAMETER[paramtype_derefed]
            except KeyError:
                raise MissingConversionException(f'{method.decl.name}: Parameter type not found >{paramtype}< ')
            
            paramnames.append(param.name)
            paramctypes.append(ctype)
            paramfmts.append(fmt)
        
        restype = type_repr(method.decl.type.type)
        
        if restype == 'void':
            resfmt, resctype = None, None
        else:
            try:
                resfmt, resctype = self.TYPECONV_RETURN[self.bindingsgenerator.deref_typedef(restype)]
            except KeyError:
                raise MissingConversionException(f'{method.decl.name}: Return type not found >{restype}< ')
    
        # First argument should always be a reference to the object itself
        assert paramctypes and paramctypes[0] == 'pylv_Obj *'
        paramnames.pop(0)
        paramctypes.pop(0)
        paramfmts.pop(0)
        
        code = startCode
        kwlist = ''.join('"%s", ' % name for name in paramnames)
        code += f'    static char *kwlist[] = {{{kwlist}NULL}};\n';
        
        crefvarlist = ''
        cvarlist = ''
        for name, ctype, fmt in zip(paramnames, paramctypes, paramfmts):
            code += f'    {ctype} {name};\n'
            if ctype == 'pylv_Obj *' : # Object, convert from Python
                crefvarlist += f', &pylv_obj_Type, &{name}'
                cvarlist += f', {name}->ref'
            elif fmt == 'O&': # struct
                crefvarlist += f', py{ctype.rstrip(" *")}_arg_converter, &{name}'
                cvarlist += f', {name}'
            else:
                crefvarlist += f', &{name}'
                cvarlist += f', {name}'
        
        code += f'    if (!PyArg_ParseTupleAndKeywords(args, kwds, "{"".join(paramfmts)}", kwlist {crefvarlist})) return NULL;\n'
        
        callcode = f'{method.decl.name}(self->ref{cvarlist})'
        
        if resctype == 'pylv_Obj *':
            # Result of function is an lv_obj; find or create the corresponding Python
            # object using pyobj_from_lv helper
            code += f'''
    LVGL_LOCK
    lv_obj_t *result = {callcode};
    LVGL_UNLOCK
    PyObject *retobj = pyobj_from_lv(result);
    
    return retobj;
'''
        
        elif resctype is None:
            code += f'''
    LVGL_LOCK         
    {callcode};
    LVGL_UNLOCK
    Py_RETURN_NONE;
'''
        elif resfmt == 'O&':
            code += f'''
    LVGL_LOCK        
    {resctype} result = {callcode};
    LVGL_UNLOCK
    return pystruct_from_lv(result);            
'''

        else:
            code += f'''
    LVGL_LOCK        
    {resctype} result = {callcode};
    LVGL_UNLOCK
'''
            if resfmt == 'p': # Py_BuildValue does not support 'p' (which is supported by PyArg_ParseTuple..)
                code += '    if (result) {Py_RETURN_TRUE;} else {Py_RETURN_FALSE;}\n'
            else:
                code += f'    return Py_BuildValue("{resfmt}", result);\n'
   
            
        
        return code + '}\n';
Exemplo n.º 10
0
    def getset(self):
   
        
        code = f'static PyGetSetDef pylv_{self.name}_getset[] = {{\n'
        bitfieldscode = ''
        

        for decl in self.get_flattened_decls():
            assert decl.name
            if self.subpath:
                offsetcode = f'(offsetof(lv_{self.basename}, {self.subpath}{decl.name})-offsetof(lv_{self.basename}, {self.subpath[:-1]}))'
            else:
                offsetcode = f'offsetof(lv_{self.basename}, {decl.name})'
            
 
            
            if isinstance(decl.type.type, (c_ast.Struct, c_ast.Union)):
                getter, setter = 'struct_get_struct', 'struct_set_struct'
                # the closure for struct & blob is a struct of PyTypObject*, offset (w.r.t. base type), size (in bytes)
                closure = f'& ((struct_closure_t){{ &pylv_{self.name}_{decl.name}_Type, {offsetcode}, sizeof(((lv_{self.basename} *)0)->{self.subpath}{decl.name})}})'
            elif decl.bitsize is not None:
                # Needs a custom getter & setter function
                getsetname = f'struct_bitfield_{self.name}_{decl.name}'
                getter, setter = 'get_' + getsetname, 'set_' + getsetname
                closure = 'NULL'
                assert(self.bindingsgenerator.deref_typedef(generate_c(decl.type.type)) in ('uint8_t', 'uint16_t', 'uint32_t')) # the following only supports unsigned values for bitfields
                bitfieldscode += f'''

static PyObject *
{getter}(StructObject *self, void *closure)
{{
    return PyLong_FromLong(((lv_{self.basename}*)(self->data))->{self.subpath}{decl.name} );
}}

static int
{setter}(StructObject *self, PyObject *value, void *closure)
{{
    long v;
    if (long_to_int(value, &v, 0, {2**int(decl.bitsize.value)-1})) return -1;
    ((lv_{self.basename}*)(self->data))->{self.subpath}{decl.name} = v;
    return 0;
}}

'''
                    
            else:
                typestr = self.bindingsgenerator.deref_typedef(type_repr(decl.type))

                if typestr in self.TYPES:
                    getter, setter = self.TYPES[typestr]
                    closure = f'(void*){offsetcode}'
                elif typestr.startswith('lv_') and (stripstart(typestr,'lv_') in self.bindingsgenerator.structs):
                    getter, setter = 'struct_get_struct', 'struct_set_struct'
                    closure = f'& ((struct_closure_t){{ &py{typestr}_Type, {offsetcode}, sizeof({typestr})}})'
                else:
                    # default: blob type
                    getter, setter = 'struct_get_struct', 'struct_set_struct'
                    closure = f'& ((struct_closure_t){{ &Blob_Type, {offsetcode}, sizeof(((lv_{self.basename} *)0)->{self.subpath}{decl.name})}})'

            
            typedoc = generate_c(decl.type).replace('\n', ' ') + (f':{decl.bitsize.value}' if decl.bitsize else '')
            code += f'    {{"{decl.name}", (getter) {getter}, (setter) {setter}, "{typedoc} {decl.name}", {closure}}},\n'
        
        code += '    {NULL}\n};\n'

        
        return bitfieldscode + code