summaryrefslogtreecommitdiff
path: root/utils/codegen/controls.py
blob: 602f15b25fb699d0edec7d728ed9d34f5307060b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2019, Google Inc.
#
# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
#
# Helper classes to handle source code generation for libcamera controls


class ControlEnum(object):
    def __init__(self, data):
        self.__data = data

    @property
    def description(self):
        """The enum description"""
        return self.__data.get('description')

    @property
    def name(self):
        """The enum name"""
        return self.__data.get('name')

    @property
    def value(self):
        """The enum value"""
        return self.__data.get('value')


class Control(object):
    def __init__(self, name, data, vendor, mode):
        self.__name = name
        self.__data = data
        self.__enum_values = None
        self.__size = None
        self.__vendor = vendor

        enum_values = data.get('enum')
        if enum_values is not None:
            self.__enum_values = [ControlEnum(enum) for enum in enum_values]

        size = self.__data.get('size')
        if size is not None:
            if len(size) == 0:
                raise RuntimeError(f'Control `{self.__name}` size must have at least one dimension')

            # Compute the total number of elements in the array. If any of the
            # array dimension is a string, the array is variable-sized.
            num_elems = 1
            for dim in size:
                if type(dim) is str:
                    num_elems = 0
                    break

                dim = int(dim)
                if dim <= 0:
                    raise RuntimeError(f'Control `{self.__name}` size must have positive values only')

                num_elems *= dim

            self.__size = num_elems

        if mode == 'properties':
            self.__direction = 'out'
        else:
            direction = self.__data.get('direction')
            if direction is None:
                raise RuntimeError(f'Control `{self.__name}` missing required field `{direction}`')
            if direction not in ['in', 'out', 'inout']:
                raise RuntimeError(f'Control `{self.__name}` direction `{direction}` is invalid; must be one of `in`, `out`, or `inout`')
            self.__direction = direction

    @property
    def description(self):
        """The control description"""
        return self.__data.get('description')

    @property
    def enum_values(self):
        """The enum values, if the control is an enumeration"""
        if self.__enum_values is None:
            return
        for enum in self.__enum_values:
            yield enum

    @property
    def enum_values_count(self):
        """The number of enum values, if the control is an enumeration"""
        if self.__enum_values is None:
            return 0
        return len(self.__enum_values)

    @property
    def is_enum(self):
        """Is the control an enumeration"""
        return self.__enum_values is not None

    @property
    def vendor(self):
        """The vendor string, or None"""
        return self.__vendor

    @property
    def name(self):
        """The control name (CamelCase)"""
        return self.__name

    @property
    def type(self):
        typ = self.__data.get('type')
        size = self.__data.get('size')

        if typ == 'string':
            return 'std::string'

        if self.__size is None:
            return typ

        if self.__size:
            return f"Span<const {typ}, {self.__size}>"
        else:
            return f"Span<const {typ}>"

    @property
    def direction(self):
        in_flag = 'ControlId::Direction::In'
        out_flag = 'ControlId::Direction::Out'

        if self.__direction == 'inout':
            return f'{in_flag} | {out_flag}'
        if self.__direction == 'in':
            return in_flag
        if self.__direction == 'out':
            return out_flag

    @property
    def element_type(self):
        return self.__data.get('type')

    @property
    def size(self):
        return self.__size