def get_c_function(self): template1A = r"""// Callback function for {packet_comment} callback """ template1B = r"""{override_comment} """ template2 = r"""static void {packet_under}_handler(TF_{device_camel} *device, {parameters}void *user_data) {{ {unuseds} {printfs}{extra_message} }} """ override_comment = self.get_formatted_override_comment( '// {0}', None, '\n// ') if override_comment == None: template1 = template1A else: template1 = template1B parameters = [] unuseds = ['(void)device;'] printfs = [] for parameter in self.get_parameters(): parameters.append(parameter.get_c_source()) unuseds += parameter.get_c_unuseds() printfs += parameter.get_c_printfs() while None in unuseds: unuseds.remove(None) unuseds.append('(void)user_data;') unuseds = common.wrap_non_empty('', '<BP>'.join(unuseds), ' // avoid unused parameter warning') unuseds = common.break_string(unuseds, '').replace('\n', '\n\t') while None in printfs: printfs.remove(None) if len(printfs) > 1: printfs.append('\ttf_hal_printf("\\n");') extra_message = self.get_formatted_extra_message( '\ttf_hal_printf("{0}\\n");').replace('%', '%%') if len(extra_message) > 0 and len(printfs) > 0: extra_message = '\n' + extra_message result = format(template1, None, self, override_comment=override_comment) + \ format(template2, self.get_device(), self, parameters=common.wrap_non_empty('', ',<BP>'.join(parameters), ',<BP>'), unuseds=unuseds, printfs='\n'.join(printfs).replace('\r\n\r', '\n\n').strip('\r').replace('\r', '\n'), extra_message=extra_message) return common.break_string(result, '{}_handler('.format(self.get_name().under))
def specializer(packet, high_level): if packet.get_type() == 'callback': return format( ':c:func:`{packet_space} <tf_{device_under}_register_{packet_under}_callback>`', packet.get_device(), packet, 0) else: return format(':c:func:`tf_{device_under}_{packet_under}`', packet.get_device(), packet, -2 if high_level else 0)
def get_c_source(self): template = r""" // Configure threshold for {packet_comment} "{option_comment}"{declarations} tf_{device_under}_set_{packet_under}_callback_threshold(&{device_initial}{arguments}, '{option_char}', {minimum_maximums}); """ minimum_maximums = [] for minimum_maximum in self.get_minimum_maximums(): minimum_maximums.append(minimum_maximum.get_c_source()) arg_declarations, arguments = self.get_c_arguments() declarations = common.wrap_non_empty( '\n', '\n'.join([ '{global_line_prefix}\t{decl}'.format( global_line_prefix=global_line_prefix, decl=decl) for decl in arg_declarations ]), '') return format(template, self.get_device(), self, declarations=declarations, arguments=common.wrap_non_empty(', ', ', '.join(arguments), ''), option_char=self.get_option_char(), option_comment=self.get_option_comment(), minimum_maximums=', '.join(minimum_maximums))
def get_c_source(self): global global_line_prefix type_ = self.get_type() if type_ == 'empty': return '' elif type_ == 'debounce_period': template = r""" // Get threshold callbacks with a debounce time of {period_sec} ({period_msec}ms) tf_{device_under}_set_debounce_period(&{device_initial}, {period_msec}); """ period_msec, period_sec = self.get_formatted_debounce_period() return format(template, self.get_device(), period_msec=period_msec, period_sec=period_sec) elif type_ == 'sleep': template = '{comment1}{global_line_prefix}\ttf_hal_sleep_us(hal, {duration} * 1000);{comment2}\n' return template.format(global_line_prefix=global_line_prefix, duration=self.get_sleep_duration(), comment1=self.get_formatted_sleep_comment1(global_line_prefix + '\t// {0}\n', '\r', '\n' + global_line_prefix + '\t// '), comment2=self.get_formatted_sleep_comment2(' // {0}', '')) elif type_ == 'wait': return None elif type_ == 'loop_header': template = '{comment}\tint i;\n\tfor(i = 0; i < {limit}; ++i) {{\n' global_line_prefix = '\t' return template.format(limit=self.get_loop_header_limit(), comment=self.get_formatted_loop_header_comment('\t// {0}\n', '', '\n\t// ')) elif type_ == 'loop_footer': global_line_prefix = '' return '\r\t}\n'
def get_c_source(self): template = '{comment1}{declarations}{global_line_prefix}\tcheck(tf_{device_under}_{packet_under}(&{device_initial}{arguments}), "call {packet_under}");{comment2}\n' arg_declarations, arguments = self.get_c_arguments() declarations = common.wrap_non_empty( '', '\n'.join([ '{global_line_prefix}\t{decl}'.format( global_line_prefix=global_line_prefix, decl=decl) for decl in arg_declarations ]), '\n') result = format(template, self.get_device(), self, global_line_prefix=global_line_prefix, declarations=declarations, arguments=common.wrap_non_empty( ',<BP>', ',<BP>'.join(arguments), ''), comment1=self.get_formatted_comment1( global_line_prefix + '\t// {0}\n', '\r', '\n' + global_line_prefix + '\t// '), comment2=self.get_formatted_comment2(' // {0}', '')) return common.break_string(result, '_{}('.format(self.get_name().under))
def get_c_source(self): templateA = r""" // Set period for {packet_comment} callback to {period_sec_short} ({period_msec}ms){declarations} check(tf_{device_under}_set_{packet_under}_period(&{device_initial}{arguments}, {period_msec}), "set {packet_comment} period"); """ templateB = r""" // Set period for {packet_comment} callback to {period_sec_short} ({period_msec}ms) // Note: The {packet_comment} callback is only called every {period_sec_long} // if the {packet_comment} has changed since the last call!{declarations} check(tf_{device_under}_set_{packet_under}_callback_period(&{device_initial}{arguments}, {period_msec}), "set {packet_comment} callback period"); """ if self.get_device().get_name().space.startswith('IMU'): template = templateA # FIXME: special hack for IMU Brick (2.0) callback behavior and name mismatch else: template = templateB period_msec, period_sec_short, period_sec_long = self.get_formatted_period() arg_declarations, arguments = self.get_c_arguments() declarations = common.wrap_non_empty('\n', '\n'.join(['{global_line_prefix}\t{decl}'.format(global_line_prefix=global_line_prefix, decl=decl) for decl in arg_declarations]), '') return format(template, self.get_device(), self, declarations=declarations, arguments=common.wrap_non_empty(', ', ', '.join(arguments), ''), period_msec=period_msec, period_sec_short=period_sec_short, period_sec_long=period_sec_long)
def get_c_source(self): template = 'TF_{device_upper}_{constant_group_upper}_{constant_upper}' return format( template, self.get_device(), constant_group_upper=self.get_constant_group().get_name().upper, constant_upper=self.get_name().upper)
def get_c_source(self): template = r""" // Register {packet_comment}<BP>callback<BP>to<BP>function<BP>{packet_under}_handler tf_{device_under}_register_{packet_under}_callback(&{device_initial}, {spaces}{packet_under}_handler, {spaces}NULL); """ result = format(template, self.get_device(), self, spaces=' ' * (len(self.get_device().get_name().under) + len(self.get_name().under) + 23)) return common.break_string(result, '// ', indent_tail='// ')
def get_c_source(self): template = r"""{global_line_prefix} // Get current {packet_comment} {global_line_prefix}{variable_declarations}; {global_line_prefix} check(tf_{device_under}_{packet_under}(&{device_initial}{arguments}{variable_references}), "get {packet_comment}"); {printfs} """ variable_declarations = [] variable_references = [] printfs = [] for result in self.get_results(): variable_declarations.append(result.get_c_variable_declaration()) variable_references.append(result.get_c_variable_reference()) printfs += result.get_c_printfs() arg_declarations, arguments = self.get_c_arguments() variable_declarations += arg_declarations merged_variable_declarations = [] for variable_declaration in variable_declarations: merged = False for merged_variable_declaration in merged_variable_declarations: if merged_variable_declaration[0] == variable_declaration[0]: merged_variable_declaration[1].append(variable_declaration[1]) merged = True break if not merged: merged_variable_declarations.append([variable_declaration[0], [variable_declaration[1]]]) variable_declarations = [] for merged_variable_declaration in merged_variable_declarations: variable_declarations.append('{0} {1}'.format(merged_variable_declaration[0], ',<BP>'.join(merged_variable_declaration[1]))) variable_declarations = common.break_string('\t' + ';<BP>'.join(variable_declarations), merged_variable_declarations[0][0] + ' ') variable_declarations = re.sub(';\n\t([ ]+)', ';\n\t', variable_declarations, flags=re.MULTILINE) while None in printfs: printfs.remove(None) result = format(template, self.get_device(), self, global_line_prefix=global_line_prefix, variable_declarations=variable_declarations, variable_references=',<BP>' + ',<BP>'.join(variable_references), printfs='\n'.join(printfs).replace('\r\n\r', '\n\n').strip('\r').replace('\r', '\n'), arguments=common.wrap_non_empty(',<BP>', ',<BP>'.join(arguments), '')) return common.break_string(result, '_{}('.format(self.get_name().under))
def get_c_functions(self, type_): functions = [] template = '.. c:function:: int tf_{device_under}_{packet_under}({params})\n\n{meta_table}{desc}\n' for packet in self.get_packets('function'): if packet.get_doc_type() != type_: continue if packet.get_name().under == 'get_api_version': continue skip = -2 if packet.has_high_level() else 0 plist = common.wrap_non_empty( ', ', packet.get_c_parameters(high_level=True), '') meta = packet.get_formatted_element_meta( lambda element, cardinality=None: element.get_c_type( 'meta', cardinality=cardinality), lambda element, index=None: element.get_c_name(index=index), output_parameter='always', prefix_elements=[ (self.get_name().under, 'TF_' + self.get_name().camel + ' *', 1, 'in') ], suffix_elements=[('e_code', 'int', 1, 'return')], stream_length_suffix='_length', high_level=True) functions.append( format(template, self, packet, skip, params=format( 'TF_{device_camel} *{device_under}{plist}', self, plist=plist), meta_table=common.make_rst_meta_table(meta), desc=packet.get_c_formatted_doc())) return ''.join(functions)
def get_c_callbacks(self): callbacks = [] template = '.. c:function:: void tf_{device_under}_register_{packet_under}_callback(TF_{device_camel} *{device_under}, TF_{device_camel}{packet_camel}Handler, void *user_data)\n{params}\n{meta_table}\n{desc}\n' param_template = { 'en': """ .. code-block:: c void handler({0}) """, 'de': """ .. code-block:: c void handler({0}) """ } for packet in self.get_packets('callback'): plist = format('TF_{device_camel} *{device_under}, ', self) + common.wrap_non_empty( '', packet.get_c_parameters(), ', ') + 'void *user_data' meta = packet.get_formatted_element_meta( lambda element, cardinality=None: element.get_c_type( 'meta', cardinality=cardinality), lambda element, index=None: element.get_c_name(index=index), prefix_elements=[(format('{device_under}', self), format('TF_{device_camel} *', self), 1, 'out')], suffix_elements=[('user_data', 'void *', 1, 'out')], stream_length_suffix='_length') callbacks.append( format(template, self, packet, params=common.select_lang(param_template).format(plist), meta_table=common.make_rst_meta_table(meta), desc=packet.get_c_formatted_doc())) return ''.join(callbacks)
def get_c_source(self): templateA = r""" // Set period for {packet_comment} callback to {period_sec_short} ({period_msec}ms){declarations} tf_{device_under}_set_{packet_under}_callback_configuration(&{device_initial}{arguments}, {period_msec}{value_has_to_change}); """ templateB = r""" // Set period for {packet_comment} callback to {period_sec_short} ({period_msec}ms) without a threshold{declarations} tf_{device_under}_set_{packet_under}_callback_configuration(&{device_initial}{arguments}, {period_msec}{value_has_to_change}, '{option_char}', {minimum_maximums}); """ templateC = r""" // Configure threshold for {packet_comment} "{option_comment}" // with a debounce period of {period_sec_short} ({period_msec}ms){declarations} tf_{device_under}_set_{packet_under}_callback_configuration(&{device_initial}{arguments}, {period_msec}{value_has_to_change}, '{option_char}', {minimum_maximums}); """ if self.get_option_char() == None: template = templateA elif self.get_option_char() == 'x': template = templateB else: template = templateC minimum_maximums = [] period_msec, period_sec_short, period_sec_long = self.get_formatted_period( ) for minimum_maximum in self.get_minimum_maximums(): minimum_maximums.append(minimum_maximum.get_c_source()) arg_declarations, arguments = self.get_c_arguments() declarations = common.wrap_non_empty( '\n', '\n'.join([ '{global_line_prefix}\t{decl}'.format( global_line_prefix=global_line_prefix, decl=decl) for decl in arg_declarations ]), '') return format(template, self.get_device(), self, declarations=declarations, arguments=common.wrap_non_empty(', ', ', '.join(arguments), ''), period_msec=period_msec, period_sec_short=period_sec_short, value_has_to_change=common.wrap_non_empty( ', ', self.get_value_has_to_change('true', 'false', ''), ''), option_char=self.get_option_char(), option_comment=self.get_option_comment(), minimum_maximums=', '.join(minimum_maximums))
def get_c_api(self): create_str = { 'en': """ .. c:function:: int tf_{device_under}_create(TF_{device_camel} *{device_under}, const char *uid, TF_HalContext *hal) {meta_table} Creates the device object ``{device_under}`` with the unique device ID ``uid`` and adds it to the HAL context ``hal``: .. code-block:: c TF_{device_camel} {device_under}; tf_{device_under}_create(&{device_under}, "YOUR_DEVICE_UID", &hal); This device object can be used after the HAL has been initialized. """, 'de': """ .. c:function:: int tf_{device_under}_create(TF_{device_camel} *{device_under}, const char *uid, TF_HalContext *hal) {meta_table} Erzeugt ein Geräteobjekt ``{device_under}`` mit der eindeutigen Geräte ID ``uid`` und fügt es dem HAL-Context ``hal`` hinzu: .. code-block:: c TF_{device_camel} {device_under}; tf_{device_under}_create(&{device_under}, "YOUR_DEVICE_UID", &ipcon); Dieses Geräteobjekt kann benutzt werden, nachdem der HAL initialisiert wurde. """ } destroy_str = { 'en': """ .. c:function:: int tf_{device_under}_destroy(TF_{device_camel} *{device_under}) {meta_table} Removes the device object ``{device_under}`` from its HAL context and destroys it. The device object cannot be used anymore afterwards. """, 'de': """ .. c:function:: int tf_{device_under}_destroy(TF_{device_camel} *{device_under}) {meta_table} Entfernt das Geräteobjekt ``{device_under}`` von dessen HAL-Context und zerstört es. Das Geräteobjekt kann hiernach nicht mehr verwendet werden. """ } c_str = { 'en': """ .. _{device_doc_rst_ref}_uc_callbacks: Callbacks ^^^^^^^^^ Callbacks can be registered to receive time critical or recurring data from the device. The registration is done with the corresponding ``tf_{device_under}_register_*_callback`` function. The ``user_data`` passed to the registration function as well as the device that triggered the callback are passed to the registered callback handler. Only one handler can be registered to a callback at the same time. To deregister a callback, call the ``tf_{device_under}_register_*_callback`` function with NULL as handler. .. note:: Using callbacks for recurring events is preferred compared to using getters. Polling for a callback requires writing one byte only. See here :ref:`api_bindings_uc_performance`. .. warning:: Calling bindings function from inside a callback handler is not allowed. See here :ref:`api_bindings_uc_thread_safety`. {callbacks} """, 'de': """ .. _{device_doc_rst_ref}_uc_callbacks: Callbacks ^^^^^^^^^ Callbacks können registriert werden um zeitkritische oder wiederkehrende Daten vom Gerät zu erhalten. Die Registrierung kann mit der entsprechenden ``tf_{device_under}_register_*_callback`` Funktion durchgeführt werden. Die ``user_data``, sowie das Gerät, dass das Callback ausgelöst hat, werden dem registrierten Callback-Handler übergeben. Nur ein Handler kann gleichzeitig auf das selbe Callback registriert werden. Um einen Handler zu deregistrieren, kann die ``tf_{device_under}_register_*_callback``-Funktion mit ``NULL`` als Handler aufgerufen werden. .. note:: Callbacks für wiederkehrende Ereignisse zu verwenden ist gegenüber der Verwendung von Abfragen zu bevorzugen. Es muss nur ein Byte abgefragt werden um zu prüfen ob ein Callback vorliegt. Siehe hier :ref:`api_bindings_uc_performance`. .. warning:: Aus Callback-Handlern heraus können keine Bindings-Funktionen verwendet werden. Siehe hier :ref:`api_bindings_uc_callbacks`. {callbacks} """ } api = { 'en': """ .. _{device_doc_rst_ref}_uc_api: API --- Most functions of the C/C++ bindings for microcontrollers return an error code (``e_code``). Possible error codes are: * TF\_\ **E**\\ _OK = 0 * TF\_\ **E**\\ _TIMEOUT = -1 * TF\_\ **E**\\ _INVALID_PARAMETER = -2 * TF\_\ **E**\\ _NOT_SUPPORTED = -3 * TF\_\ **E**\\ _UNKNOWN_ERROR_CODE = -4 * TF\_\ **E**\\ _STREAM_OUT_OF_SYNC = -5 * TF\_\ **E**\\ _INVALID_CHAR_IN_UID = -6 * TF\_\ **E**\\ _UID_TOO_LONG = -7 * TF\_\ **E**\\ _UID_OVERFLOW = -8 * TF\_\ **E**\\ _TOO_MANY_DEVICES = -9 * TF\_\ **E**\\ _DEVICE_NOT_FOUND = -10 * TF\_\ **E**\\ _WRONG_DEVICE_TYPE = -11 * TF\_\ **E**\\ _LOCKED = -12 * TF\_\ **E**\\ _PORT_NOT_FOUND = -13 (as defined in :file:`errors.h`) as well as the errors returned from the hardware abstraction layer (HAL) that is used. Use :cpp:func`tf_hal_strerror` (defined in the HAL's header file) to get an error string for an error code. Data returned from the device, when a getter is called, is handled via output parameters. These parameters are labeled with the ``ret_`` prefix. The bindings will not write to an output parameter if NULL or nullptr is passed. This can be used to ignore outputs that you are not interested in. **None of the functions listed below are thread-safe.** See the :ref:`API bindings description <api_bindings_uc>` for details. {doc_str} {api_str} """, 'de': """ .. _{device_doc_rst_ref}_uc_api: API --- Die meistens Funktionen der C/C++ Bindings für Mikrocontroller geben einen Fehlercode (``e_code``) zurück Mögliche Fehlercodes sind: * TF\_\ **E**\\ _OK = 0 * TF\_\ **E**\\ _TIMEOUT = -1 * TF\_\ **E**\\ _INVALID_PARAMETER = -2 * TF\_\ **E**\\ _NOT_SUPPORTED = -3 * TF\_\ **E**\\ _UNKNOWN_ERROR_CODE = -4 * TF\_\ **E**\\ _STREAM_OUT_OF_SYNC = -5 * TF\_\ **E**\\ _INVALID_CHAR_IN_UID = -6 * TF\_\ **E**\\ _UID_TOO_LONG = -7 * TF\_\ **E**\\ _UID_OVERFLOW = -8 * TF\_\ **E**\\ _TOO_MANY_DEVICES = -9 * TF\_\ **E**\\ _DEVICE_NOT_FOUND = -10 * TF\_\ **E**\\ _WRONG_DEVICE_TYPE = -11 * TF\_\ **E**\\ _CALLBACK_EXEC = -12 * TF\_\ **E**\\ _PORT_NOT_FOUND = -13 (wie in :file:`errors.h` definiert), sowie die Fehlercodes des verwendeten Hardware-Abstraction-Layers (HALs). Mit ``tf_hal_strerror`` (im Header das HALs definiert) kann ein Fehlerstring zu einem Fehlercode abgefragt werden. Vom Gerät zurückgegebene Daten werden, wenn eine Abfrage aufgerufen wurde, über Ausgabeparameter gehandhabt. Diese Parameter sind mit dem ``ret_`` Präfix gekennzeichnet. Die Bindings schreiben einen Ausgabeparameter nicht, wenn NULL bzw. nullptr übergeben wird. So können uninteressante Ausgaben ignoriert werden. **Keine der folgend aufgelisteten Funktionen ist Thread-sicher.** Details finden sich in der :ref:`Beschreibung der API-Bindings <api_bindings_uc>`. {doc_str} {api_str} """ } const_str = { 'en': """ .. _{device_doc_rst_ref}_uc_constants: Constants ^^^^^^^^^ .. c:var:: TF_{device_upper}_DEVICE_IDENTIFIER This constant is used to identify a {device_display}. The functions :c:func:`tf_{device_under}_get_identity` and :c:func:`tf_hal_get_device_info` have a ``device_identifier`` output parameter to specify the Brick's or Bricklet's type. .. c:var:: TF_{device_upper}_DEVICE_DISPLAY_NAME This constant represents the human readable name of a {device_display}. """, 'de': """ .. _{device_doc_rst_ref}_uc_constants: Konstanten ^^^^^^^^^^ .. c:var:: TF_{device_upper}_DEVICE_IDENTIFIER Diese Konstante wird verwendet um {article} {device_display} zu identifizieren. Die Funktionen :c:func:`tf_{device_under}_get_identity` und :c:func:`tf_hal_get_device_info` haben einen ``device_identifier`` Ausgabe-Parameter um den Typ des Bricks oder Bricklets anzugeben. .. c:var:: TF_{device_upper}_DEVICE_DISPLAY_NAME Diese Konstante stellt den Anzeigenamen eines {device_display} dar. """ } create_meta = common.format_simple_element_meta([ (format('{device_under}', self), format('TF_{device_camel} *', self), 1, 'in'), ('uid', 'const char *', 1, 'in'), ('hal', 'TF_HalContext *', 1, 'in') ]) create_meta_table = common.make_rst_meta_table(create_meta) cre = format(common.select_lang(create_str), self, meta_table=create_meta_table) destroy_meta = common.format_simple_element_meta([ (format('{device_under}', self), format('TF_{device_camel} *', self), 1, 'in') ]) destroy_meta_table = common.make_rst_meta_table(destroy_meta) des = format(common.select_lang(destroy_str), self, meta_table=destroy_meta_table) bf = self.get_c_functions('bf') af = self.get_c_functions('af') ccf = self.get_c_functions('ccf') c = self.get_c_callbacks() vf = self.get_c_functions('vf') if_ = self.get_c_functions('if') api_str = '' if bf: api_str += common.select_lang(common.bf_str).format(cre + des, bf) if af: api_str += common.select_lang(common.af_str).format(af) if c: api_str += common.select_lang(common.ccf_str).format('', ccf) api_str += format(common.select_lang(c_str), self, device_doc_rst_ref=self.get_doc_rst_ref_name(), callbacks=c, padding=' ' * len(self.get_name().under)) if vf: api_str += common.select_lang(common.vf_str).format(vf) if if_: api_str += common.select_lang(common.if_str).format(if_) article = 'ein' if self.is_brick(): article = 'einen' api_str += format(common.select_lang(const_str), self, device_doc_rst_ref=self.get_doc_rst_ref_name(), article=article) return format(common.select_lang(api), self, device_doc_rst_ref=self.get_doc_rst_ref_name(), doc_str=self.specialize_c_doc_function_links( common.select_lang(self.get_doc())), api_str=api_str)
def get_c_source(self): template = r"""// This example is not self-contained. // It requres usage of the example driver specific to your platform. // See the HAL documentation. {defines}{includes}{incomplete}{description} #define UID "{dummy_uid}" // Change {dummy_uid} to the UID of your {device_display} void check(int rc, const char* msg); void example_setup(TF_HalContext *hal); void example_loop(TF_HalContext *hal); {functions} static TF_{device_camel} {device_initial}; void example_setup(TF_HalContext *hal) {{ // Create device object check(tf_{device_under}_create(&{device_initial}, UID, hal), "create device object"); {sources}}} void example_loop(TF_HalContext *hal) {{ // Poll for callbacks tf_hal_callback_tick(hal, 0); }} """ if self.is_incomplete(): incomplete = '\n\n// FIXME: This example is incomplete' else: incomplete = '' if self.get_description() != None: description = '\n\n// {0}'.format(self.get_description().replace( '\n', '\n// ')) else: description = '' defines = [] includes = [] functions = [] sources = [] cleanups = [] for function in self.get_functions(): defines += function.get_c_defines() includes += function.get_c_includes() functions.append(function.get_c_function()) sources.append(function.get_c_source()) for cleanup in self.get_cleanups(): defines += cleanup.get_c_defines() includes += cleanup.get_c_includes() functions.append(cleanup.get_c_function()) cleanups.append(cleanup.get_c_source()) if len(includes) > 0: includes += [''] includes += [ '#include "bindings/hal_common.h"', format('#include "bindings/{category_under}_{device_under}.h"', self.get_device()) ] unique_includes = [] for include in includes: if include not in unique_includes: unique_includes.append(include) unique_defines = [] for define in defines: if define not in unique_defines: unique_defines.append(define) while None in functions: functions.remove(None) while None in sources: sources.remove(None) if len(sources) == 0: sources = ['\t// TODO: Add example code here\n'] while None in cleanups: cleanups.remove(None) return format( template, self.get_device(), defines=common.wrap_non_empty('', '\n'.join(unique_defines), '\n\n'), includes=common.wrap_non_empty('', '\n'.join(unique_includes), ''), incomplete=incomplete, description=description, dummy_uid=self.get_dummy_uid(), functions=common.wrap_non_empty('\n', '\n'.join(functions), ''), sources='\n' + '\n'.join(sources).replace('\n\r', '').lstrip('\r'))