2 from __future__ import print_function
3 from collections import OrderedDict
8 class quoted(str): pass
10 def quoted_presenter(dumper, data):
11 return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
12 yaml.add_representer(quoted, quoted_presenter)
14 class literal(str): pass
16 def literal_presenter(dumper, data):
17 return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
18 yaml.add_representer(literal, literal_presenter)
20 def ordered_dict_presenter(dumper, data):
21 return dumper.represent_dict(data.items())
22 yaml.add_representer(OrderedDict, ordered_dict_presenter)
24 def dict_constructor(loader, node):
25 return OrderedDict(loader.construct_pairs(node))
26 _mapping_tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG
27 yaml.add_constructor(_mapping_tag, dict_constructor)
29 class IntField(object):
30 def __init__(self, name, position, length, signed):
32 self.position = position
36 if not self.length in [1, 2, 4]:
37 raise Exception("bad length " + str(self.length))
39 self.user_type = ('u' if not signed else '') + 'int' + str(length * 8) + '_t'
42 return "{0}* {1}".format(self.user_type, self.name)
46 return "*{0} = data[{1}];".format(self.name, self.position)
47 elif self.length == 2:
48 return "*{0} = SW_TO_SHORT(data + {1});".format(self.name, self.position)
49 elif self.length == 4:
50 return "*{0} = DW_TO_INT(data + {1});".format(self.name, self.position)
53 return "{0} {1}".format(self.user_type, self.name)
57 return "data[{0}] = {1};".format(self.position, self.name)
58 elif self.length == 2:
59 return "SHORT_TO_SW({0}, data + {1});".format(self.name, self.position)
60 elif self.length == 4:
61 return "INT_TO_DW({0}, data + {1});".format(self.name, self.position)
64 rep = [('position', self.position), ('length', self.length)]
66 rep.append(('signed', True))
71 return IntField(spec['name'], spec['position'], spec['length'], spec['signed'] if signed in spec else False)
73 def load_field(name, spec):
74 if spec['type'] == 'int':
75 return IntField(name, spec['position'], spec['length'], spec.get('signed', False))
77 raise Exception("unknown field type '{0}'".format(spec['type']))
79 GETTER_TEMPLATE = """/** @ingroup ctrl
81 * @param devh UVC device handle
83 * @param req_code UVC_GET_* request to execute
85 uvc_error_t uvc_get_{control_name}(uvc_device_handle_t *devh, {args_signature}, enum uvc_req_code req_code) {{
86 uint8_t data[{control_length}];
89 ret = libusb_control_transfer(
91 REQ_TYPE_GET, req_code,
93 {unit_fn} << 8 | devh->info->ctrl_if.bInterfaceNumber,
98 if (ret == sizeof(data)) {{
107 SETTER_TEMPLATE = """/** @ingroup ctrl
109 * @param devh UVC device handle
112 uvc_error_t uvc_set_{control_name}(uvc_device_handle_t *devh, {args_signature}) {{
113 uint8_t data[{control_length}];
118 ret = libusb_control_transfer(
120 REQ_TYPE_SET, UVC_SET_CUR,
122 {unit_fn} << 8 | devh->info->ctrl_if.bInterfaceNumber,
127 if (ret == sizeof(data))
134 def gen_decl(unit_name, unit, control_name, control):
135 fields = [(load_field(field_name, field_details), field_details['doc']) for field_name, field_details in control['fields'].items()] if 'fields' in control else []
137 get_args_signature = ', '.join([field.getter_sig() for (field, desc) in fields])
138 set_args_signature = ', '.join([field.setter_sig() for (field, desc) in fields])
140 return "uvc_error_t uvc_get_{function_name}(uvc_device_handle_t *devh, {args_signature}, enum uvc_req_code req_code);\n".format(**{
141 "function_name": control_name,
142 "args_signature": get_args_signature
143 }) + "uvc_error_t uvc_set_{function_name}(uvc_device_handle_t *devh, {args_signature});\n".format(**{
144 "function_name": control_name,
145 "args_signature": set_args_signature
148 def gen_ctrl(unit_name, unit, control_name, control):
149 fields = [(load_field(field_name, field_details), field_details['doc']) for field_name, field_details in control['fields'].items()] if 'fields' in control else []
151 get_args_signature = ', '.join([field.getter_sig() for (field, desc) in fields])
152 set_args_signature = ', '.join([field.setter_sig() for (field, desc) in fields])
153 unpack = "\n ".join([field.unpack() for (field, desc) in fields])
154 pack = "\n ".join([field.pack() for (field, desc) in fields])
156 get_gen_doc_raw = None
157 set_gen_doc_raw = None
162 if isinstance(doc, str):
163 get_gen_doc_raw = "\n * ".join(doc.splitlines())
164 set_gen_doc_raw = get_gen_doc_raw
167 get_gen_doc_raw = "\n * ".join(doc['get'].splitlines())
169 set_gen_doc_raw = "\n * ".join(doc['set'].splitlines())
171 if get_gen_doc_raw is not None:
172 get_gen_doc = get_gen_doc_raw.format(gets_sets='Reads')
174 get_gen_doc = '@brief Reads the ' + control['control'] + ' control.'
176 if set_gen_doc_raw is not None:
177 set_gen_doc = set_gen_doc_raw.format(gets_sets='Sets')
179 set_gen_doc = '@brief Sets the ' + control['control'] + ' control.'
181 get_args_doc = "\n * ".join(["@param[out] {0} {1}".format(field.name, desc) for (field, desc) in fields])
182 set_args_doc = "\n * ".join(["@param {0} {1}".format(field.name, desc) for (field, desc) in fields])
184 control_code = 'UVC_' + unit['control_prefix'] + '_' + control['control'] + '_CONTROL'
186 unit_fn = "uvc_get_camera_terminal(devh)->bTerminalID" if (unit_name == "camera_terminal") else ("uvc_get_" + unit_name + "s(devh)->bUnitID")
188 return GETTER_TEMPLATE.format(
191 control_name=control_name,
192 control_code=control_code,
193 control_length=control['length'],
194 args_signature=get_args_signature,
195 args_doc=get_args_doc,
197 unpack=unpack) + "\n\n" + SETTER_TEMPLATE.format(
200 control_name=control_name,
201 control_code=control_code,
202 control_length=control['length'],
203 args_signature=set_args_signature,
204 args_doc=set_args_doc,
209 def export_unit(unit):
211 def wrap_doc_entry(entry):
213 return literal(entry)
217 if isinstance(doc, str):
218 return wrap_doc_entry(doc)
220 return OrderedDict([(mode, wrap_doc_entry(text)) for mode, text in doc.items()])
222 def fmt_ctrl(control_name, control_details):
223 contents = OrderedDict()
224 contents['control'] = control_details['control']
225 contents['length'] = control_details['length']
226 contents['fields'] = control_details['fields']
228 if 'doc' in control_details:
229 contents['doc'] = fmt_doc(control_details['doc'])
231 return (control_name, contents)
233 unit_out = OrderedDict()
234 unit_out['type'] = unit['type']
236 unit_out['guid'] = unit['guid']
237 if 'description' in unit:
238 unit_out['description'] = unit['description']
239 if 'control_prefix' in unit:
240 unit_out['control_prefix'] = unit['control_prefix']
241 unit_out['controls'] = OrderedDict([fmt_ctrl(ctrl_name, ctrl_details) for ctrl_name, ctrl_details in unit['controls'].items()])
244 if __name__ == '__main__':
246 opts, args = getopt.getopt(sys.argv[1:], "hi:", ["help", "input="])
247 except getopt.GetoptError as err:
254 for opt, val in opts:
255 if opt in ('-h', '--help'):
258 elif opt in ('-i', '--input'):
263 if arg in ('def', 'decl', 'yaml'):
267 print("Can't specify more than one mode")
270 print("Invalid mode '{0}'".format(arg))
274 for input_file in inputs:
275 with open(input_file, "r") as fp:
276 units = yaml.load(fp)['units']
277 for unit_name, unit_details in units.iteritems():
278 yield unit_name, unit_details
281 print("""/* This is an AUTO-GENERATED file! Update it with the output of `ctrl-gen.py def`. */
282 #include "libuvc/libuvc.h"
283 #include "libuvc/libuvc_internal.h"
285 static const int REQ_TYPE_SET = 0x21;
286 static const int REQ_TYPE_GET = 0xa1;
292 exported_units = OrderedDict()
293 for unit_name, unit_details in iterunits():
294 exported_units[unit_name] = export_unit(unit_details)
296 yaml.dump({'units': exported_units}, sys.stdout, default_flow_style=False)
299 for unit_name, unit_details in iterunits():
300 for control_name, control_details in unit_details['controls'].iteritems():
301 code = fun(unit_name, unit_details, control_name, control_details)