def get_openhab_param_entries(self, params): meta_table_entries = [] for i, p in enumerate(params): param_meta = [] entries = [('Type', p.type if p.options is None else 'Choice'), ('Default', p.default if p.options is None else [x[0] for x in p.options if x[1] == p.default][0]), ('Unit', p.unit), ('Min', p.min), ('Max', p.max), ('Step', p.step)] for l, r in entries: if r is not None: param_meta.append('{}: {}'.format(l, r)) if p.description is None: raise common.GeneratorError( "Parameter {} has no description.".format(p.label)) else: entry_tup = ('plain', 'Parameters', [('plain', p.label, ', '.join(param_meta)), common.shift_right(unescape(p.description), 2)]) if p.options is not None: entry_tup[2].append('{}: {}'.format( 'Options', ', '.join([x[0] for x in p.options]))) if i != len(params) - 1: entry_tup[2].append(unescape('<br/>')) meta_table_entries.append(entry_tup) return meta_table_entries
def specialize_doc_rst_links(self, text, specializer, prefix=None): for keyword, type_ in [('func', 'function'), ('cb', 'callback')]: for packet in self.get_packets(type_): names = [packet.get_name().space] if packet.has_high_level(): names.append(packet.get_name(skip=-2).space) for name in names: generic_name = ':{0}:`{1}`'.format(keyword, name) special_name, text = specializer( text, packet, packet.has_high_level() and not name.endswith(' Low Level')) text = text.replace(generic_name, special_name) if prefix != None: p = '(?<!:' + prefix + ')(:' + keyword + ':`[^`]*`)' else: p = '(:' + keyword + ':`[^`]*`)' m = re.search(p, text) if m != None: raise common.GeneratorError('Unknown :{0}: found: {1}'.format( keyword, m.group(1))) return text
def language_from_filename(filename): if filename.startswith('matlab_'): return 'matlab' elif filename.startswith('octave_'): return 'octave_fixed' else: raise common.GeneratorError('Invalid filename ' + filename)
def get_perl_default_item_value(self): value = PerlElement.perl_default_item_values[self.get_type()] if value == None: common.GeneratorError('Invalid array item type: ' + self.get_type()) return value
def language_from_filename(filename): if filename.endswith('.js'): return 'javascript' elif filename.endswith('.html'): return 'html' else: raise common.GeneratorError('Invalid filename ' + filename)
def title_from_filename(filename): if filename.endswith('.js'): filename = filename.replace('Example', '').replace('.js', '') return common.camel_to_space(filename) + ' (Node.js)' elif filename.endswith('.html'): filename = filename.replace('Example', '').replace('.html', '') return common.camel_to_space(filename) + ' (HTML)' else: raise common.GeneratorError('Invalid filename ' + filename)
def title_from_filename(filename): title = filename.replace('matlab_example_', '').replace('octave_example_', '').replace('.m', '') if filename.startswith('matlab_'): return common.under_to_space(title) + ' (MATLAB)' elif filename.startswith('octave_'): return common.under_to_space(title) + ' (Octave)' else: raise common.GeneratorError('Invalid filename ' + filename)
def get_csharp_default_value(self): if self.get_cardinality() != 1: return 'null' else: value = CSharpElement.csharp_default_item_values[self.get_type()] if value == None: common.GeneratorError('Invalid array item type: ' + self.get_type()) return value
def get_c_parameters(self, high_level=False): parameters = [] packet_type = self.get_type() for element in self.get_elements(high_level=high_level): element_type = element.get_c_type('signature') modifier = '' name = element.get_name().under direction = element.get_direction() role = element.get_role() array = '' if direction == 'out' and packet_type == 'function': modifier = '*' name = 'ret_{0}'.format(name) if role == 'stream_data': if direction == 'in' and packet_type == 'function': modifier = '*' elif direction == 'out' and packet_type == 'callback': modifier = '*' if role != 'stream_data' and element.get_cardinality() > 1: modifier = '' array = '[{0}]'.format(element.get_cardinality()) parameters.append('{0} {1}{2}{3}'.format(element_type, modifier, name, array)) length_elements = self.get_elements(role='stream_length') chunk_offset_elements = self.get_elements( role='stream_chunk_offset') if role == 'stream_data' and (direction == 'out' or len(length_elements) > 0): if direction == 'out' and packet_type == 'function': modifier = '*' else: modifier = '' if len(length_elements) > 0: element_type = length_elements[0].get_c_type('signature') elif len(chunk_offset_elements) > 0: element_type = chunk_offset_elements[0].get_c_type( 'signature') else: raise common.GeneratorError('Malformed stream config') parameters.append('{0} {1}{2}_length'.format( element_type, modifier, name)) return ', '.join(parameters)
def __init__(self, root_dir, extra_paths): common.Tester.__init__(self, 'delphi', '.pas', root_dir, extra_paths=extra_paths) exit_code, output = common.check_output_and_error( ['gcc', '--print-file-name', 'crtbeginS.o']) if exit_code != 0: raise common.GeneratorError( 'Failed to run gcc --print-file-name crtbeginS.o: exit_code: {}\n\t{}' .format(exit_code, output)) self.lib_path = os.path.dirname(output)
def get_csharp_source(self): function_names = self.get_packet_names('function') callback_names = self.get_packet_names('callback') for callback_name in callback_names: if callback_name + ' Callback' in function_names: raise common.GeneratorError( "Generated callback name '{0}[ Callback]' collides with function name '{0} Callback'" .format(callback_name)) source = self.get_csharp_import() source += self.get_csharp_class() source += self.get_csharp_function_id_definitions() source += self.get_csharp_constants() source += self.get_csharp_delegates() source += self.get_csharp_constructor() source += self.get_csharp_response_expected() source += self.get_csharp_methods() source += self.get_csharp_callbacks() return source
def test(self, cookie, tmp_dir, path, extra): uses_libgd = False with open(path, 'r') as f: uses_libgd = '#include <gd.h>' in f.read() # skip OLED scribble example because mingw32 has no libgd package if self.compiler.startswith('mingw32-') and uses_libgd: self.handle_result(cookie, 0, '>>> skipping') return if extra: shutil.copy(path, tmp_dir) path = os.path.join(tmp_dir, os.path.split(path)[-1]) output = path[:-2] if not extra and '/brick' in path: dirname = os.path.split(path)[0] device = os.path.join(tmp_dir, 'source/bindings/{0}_{1}.c'.format(os.path.split(os.path.split(dirname)[0])[-1], os.path.split(dirname)[-1])) else: device = '' args = [] if self.compiler == 'gcc': args += ['gcc', '-std=c99', '-pthread'] elif self.compiler == 'g++': args += ['g++', '-std=c++98', '-pthread'] elif self.compiler == 'mingw32-gcc': args += ['x86_64-w64-mingw32-gcc', '-Wno-error=return-type'] elif self.compiler == 'mingw32-g++': args += ['x86_64-w64-mingw32-g++', '-Wno-error=return-type'] elif self.compiler == 'clang': args += ['clang', '-std=c99', '-pthread', '-Weverything', '-Wno-padded'] elif self.compiler == 'scan-build clang': args += ['scan-build', 'clang', '-std=c99', '-pthread'] else: raise common.GeneratorError('Invalid compiler ' + self.compiler) args += ['-Wall', '-Wextra', '-Werror', '-O2', '-I' + os.path.join(tmp_dir, 'source'), '-o', output, os.path.join(tmp_dir, 'source/bindings/base58.c'), os.path.join(tmp_dir, 'source/bindings/bricklet_unknown.c'), os.path.join(tmp_dir, 'source/bindings/endian_convert.c'), os.path.join(tmp_dir, 'source/bindings/hal_common.c'), os.path.join(tmp_dir, 'source/bindings/packetbuffer.c'), os.path.join(tmp_dir, 'source/bindings/pearson_hash.c'), os.path.join(tmp_dir, 'source/bindings/spitfp.c'), os.path.join(tmp_dir, 'source/bindings/tfp.c'), os.path.join(tmp_dir, 'source/hal_fake/hal_fake.c'), os.path.join(tmp_dir, 'source/hal_fake/example_driver.c')] if len(device) > 0: args.append(device) elif extra: dependencies = glob.glob(os.path.join(tmp_dir, 'source/*.c')) dependencies.remove(os.path.join(tmp_dir, 'source/ip_connection.c')) args.append('-Wno-error=unused-parameter') args += dependencies args.append(path) if self.compiler.startswith('mingw32-'): args += ['-lws2_32'] if uses_libgd: args += ['-lm', '-lgd'] self.execute(cookie, args)
def specializer(text, packet, high_level): # Device, link to be removed (the replacement will only fail if this is in text), replacements special_cases = [ ('CAN', ':cb:`Frame Read`', [(""" Instead of polling with this function, you can also use callbacks. See the :func:`Enable Frame Read Callback` function and the :cb:`Frame Read` callback. """, ''), (""" Instead of polling with this function, you can also use callbacks. See the :func:`Set Frame Read Callback Configuration` function and the :cb:`Frame Read` callback. """, ''), (""" function. Using the :cb:`Frame Read` callback ensures that the read buffer can not overflow. """, """ function. """), (""" function. Using the :cb:`Frame Read` callback ensures that the read backlog can not overflow. """, """ function. """)]), ('RS232', ':cb:`Read`', [(""" Instead of polling with this function, you can also use callbacks. See :func:`Enable Read Callback` and :cb:`Read` callback. """, ''), (""" Instead of polling with this function, you can also use callbacks. But note that this function will return available data only when the read callback is disabled. See :func:`Enable Read Callback` and :cb:`Read` callback. """, "")]), ('RS485', ':cb:`Read`', [(""" Instead of polling with this function, you can also use callbacks. But note that this function will return available data only when the read callback is disabled. See :func:`Enable Read Callback` and :cb:`Read` callback. """, '')]), ('DMX', ':cb:`Frame`', [("""Instead of polling this function you can also use the :cb:`Frame` callback. You can enable it with :func:`Set Frame Callback Config`. """, '')]), ('Industrial Digital In 4', ':func:`Set Group`', [(""" If no groups are used (see :func:`Set Group`), the pins correspond to the markings on the IndustrialDigital In 4 Bricklet. If groups are used, the pins correspond to the element in the group. Element 1 in the group will get pins 0-3, element 2 pins 4-7, element 3 pins 8-11 and element 4 pins 12-15. """, ''), (""" The edge counters use the grouping as set by :func:`Set Group`. """, '')]), ('Industrial Digital Out 4', ':func:`Set Group`', [(""" If no groups are used (see :func:`Set Group`), the pins correspond to the markings on the Industrial Digital Out 4 Bricklet. If groups are used, the pins correspond to the element in the group. Element 1 in the group will get pins 0-3, element 2 pins 4-7, element 3 pins 8-11 and element 4 pins 12-15. """, '')]), ('Industrial Quad Relay', ':func:`Set Group`', [(""" If no groups are used (see :func:`Set Group`), the pins correspond to the markings on the Industrial Quad Relay Bricklet. If groups are used, the pins correspond to the element in the group. Element 1 in the group will get pins 0-3, element 2 pins 4-7, element 3 pins 8-11 and element 4 pins 12-15. """, '')]), ('PTC V2', ':func:`Set Sensor Connected Callback Configuration`', [ (""" You can set the callback configuration with :func:`Set Sensor Connected Callback Configuration`.""", '') ]), ('Joystick V2', ':func:`Set Pressed Callback Configuration`', [(""" and set the period with :func:`Set Pressed Callback Configuration`""", '')]) ] for dev, link, replacements in special_cases: if dev not in self.get_name().space: continue if link not in text: continue for to_replace, replacement in replacements: if to_replace in text: text = text.replace(to_replace, replacement) break else: raise common.GeneratorError( "openhab: {} {} No replacement found!".format( dev, link)) channel = None # Handle 'All Data/Values' cases: Cut out the complete paragraph mentioning the callback. needle = ':cb:`{}`'.format( packet.get_name(skip=-2 if high_level else 0).space) if 'All' in packet.name.words and needle in text: channel = 'All' if packet.get_type() == 'callback': needle_idx = text.find(needle) paragraph_start = text.rfind('\n\n', 0, needle_idx) paragraph_end = text.rfind('\n\n', needle_idx) if paragraph_start < 0: paragraph_start = 0 if paragraph_end < 0: paragraph_end = len(text) - 1 text = text[:paragraph_start] + text[paragraph_end:] return '', text else: return ':openhab:func:`{1}() <{0}::{2}{1}>`'.format( packet.get_device().get_java_class_name(), packet.get_name(skip=-2 if high_level else 0).camel, packet.get_device().get_category().headless + packet.get_device().get_name().camel), text # Handle EEPROM/Flash cases: Remove link, add note instead. to_remove = [ ('BrickletAirQuality', 'SetBackgroundCalibrationDuration'), ('BrickletAnalogInV3', 'SetCalibration'), ('BrickletCompass', 'SetCalibration'), ('BrickletCO2V2', 'SetTemperatureOffset'), ('BrickletDistanceIRV2', 'SetSensorType'), ('BrickletDistanceIR', 'SetSamplingPoint'), ('BrickletEnergyMonitor', 'SetTransformerCalibration'), ('BrickletIndustrialDualAnalogInV2', 'SetCalibration'), ('BrickletIndustrialDualAnalogInV2', 'SetCalibration'), ('BrickletIndustrialDualAnalogIn', 'SetCalibration'), ('BrickletIndustrialDualAnalogIn', 'SetCalibration'), ('BrickletJoystickV2', 'Calibrate'), ('BrickletJoystick', 'Calibrate'), ('BrickletLaserRangeFinderV2', 'SetOffsetCalibration'), ('BrickletRGBLEDButton', 'SetColorCalibration'), ('BrickletRealTimeClockV2', 'SetOffset'), ('BrickletRealTimeClock', 'SetOffset'), ('BrickletTemperatureIRV2', 'SetEmissivity'), ('BrickletTemperatureIRV2', 'SetEmissivity'), ('BrickletTemperatureIR', 'SetEmissivity'), ('BrickletTemperatureIR', 'SetEmissivity'), ('BrickletVoltageCurrentV2', 'SetCalibration'), ('BrickletVoltageCurrent', 'SetCalibration'), ('BrickIMU', 'SetCalibration'), ('BrickMaster', 'SetExtensionType'), ('BrickMaster', 'SetChibiAddress'), ('BrickMaster', 'SetChibiMasterAddress'), ('BrickMaster', 'SetChibiSlaveAddress'), ('BrickMaster', 'SetChibiFrequency'), ('BrickMaster', 'SetChibiChannel'), ('BrickMaster', 'SetRS485Address'), ('BrickMaster', 'SetRS485SlaveAddress'), ('BrickMaster', 'SetRS485Configuration'), ('BrickMaster', 'SetWifiConfiguration'), ('BrickMaster', 'SetWifiEncryption'), ('BrickMaster', 'SetWifiCertificate'), ('BrickMaster', 'SetWifiPowerMode'), ('BrickMaster', 'SetWifiRegulatoryDomain'), ('BrickMaster', 'SetLongWifiKey'), ('BrickMaster', 'SetWifiHostname'), ('BrickMaster', 'SetWifiAuthenticationSecret'), ('BrickMaster', 'SetEthernetConfiguration'), ('BrickMaster', 'SetEthernetConfiguration'), ('BrickMaster', 'SetEthernetAuthenticationSecret'), ('BrickMaster', 'SetWifi2AuthenticationSecret'), ('BrickMaster', 'SetWifi2Configuration'), ('BrickMaster', 'SetWifi2ClientConfiguration'), ('BrickMaster', 'SetWifi2ClientHostname'), ('BrickMaster', 'SetWifi2APConfiguration'), ('BrickMaster', 'SetWifi2MeshConfiguration'), ('BrickMaster', 'SetWifi2MeshRouterSSID'), ('BrickletLoadCell', 'SetConfiguration'), ('BrickletPiezoSpeaker', 'Calibrate') ] current_dev = self.get_category().camel + self.get_name().camel current_fn = packet.get_name().camel for dev, fn in to_remove: if dev != current_dev: continue if fn != current_fn: continue return '*This function is not available in openHAB*. *Please use Brick Viewer to change persistant device settings*', text # Try to find a channel for the link def match_name(gp, sp, cp, skip_haystack, skip_needle, skipped): return any(x.get_name(skip=skip_haystack).space == 'Get ' + packet.get_name(skip_needle).space for x in gp if skipped in x.get_name().space) or \ any(x.get_name(skip=skip_haystack).space == 'Set ' + packet.get_name(skip_needle).space for x in sp if skipped in x.get_name().space) or \ any(x.get_name(skip=skip_haystack).space == packet.get_name(skip_needle).space for x in gp if skipped in x.get_name().space) or \ any(x.get_name(skip=skip_haystack).space == packet.get_name(skip_needle).space for x in sp if skipped in x.get_name().space) or \ any(x.get_name(skip=skip_haystack).space == packet.get_name(skip_needle).space for x in cp if skipped in x.get_name().space) for c in self.oh.channels: # skip=-2 for low level, skip=-1 for reached gp = [x.packet for x in c.getters] sp = [x.packet for x in c.setters] cp = [x.packet for x in c.callbacks] if match_name(gp, sp, cp, skip_haystack=0, skip_needle=0, skipped=''): channel = c break if 'Low Level' in packet.get_name().space: if match_name(gp, sp, cp, skip_haystack=-2, skip_needle=-2, skipped='Low Level'): channel = c break if 'Reached' in packet.get_name().space: if match_name(gp, sp, cp, skip_haystack=0, skip_needle=-1, skipped='Reached'): channel = c break if channel is not None: return ':openhab:chan:`{label} <{device}::{label}>`'.format( label=channel.get_label(), device=packet.get_device().get_java_class_name()), text # Check if the function is used by the thing itself for configuration. for p in self.oh.params: if p.packet is not None and p.packet.get_name( ).space == packet.get_name().space: if p is not None: return 'the thing configuration', text # Try to find a channel that uses the linked function for configuration. for c in self.oh.channels: for p in c.type.params: if p.packet is not None and p.packet.get_name( ).space == packet.get_name().space: return 'the configuration of :openhab:chan:`{label} <{device}::{label}>`'.format( label=c.get_label(), device=packet.get_device().get_java_class_name( )), text # Try to map function to an action for a in self.oh.actions: if a.fn.get_name().space == packet.get_name().space: return ':openhab:func:`{1}() <{0}::{2}{1}>`'.format( packet.get_device().get_java_class_name(), packet.get_name(skip=-2 if high_level else 0).camel, packet.get_device().get_category().headless + packet.get_device().get_name().camel), text # This is the last resort, typically only used for links that will not show up in the documentation anyway. if packet.get_type() == 'callback': if channel is None: return '', text return ':openhab:chan:`{label} <{device}::{label}>`'.format( label=channel.get_label(), device=packet.get_device().get_java_class_name()), text else: return ':openhab:func:`{1}() <{0}::{2}{1}>`'.format( packet.get_device().get_java_class_name(), packet.get_name(skip=-2 if high_level else 0).camel, packet.get_device().get_category().headless + packet.get_device().get_name().camel), text
def finish(self): if self.get_config_name().space != 'Tinkerforge': return root_dir = self.get_root_dir() for src, dst in self.file_dests.items(): shutil.copy(src, dst) binding_dir = os.path.join(self.get_bindings_dir(), '..', 'openhab2-addons', 'bundles', 'org.openhab.binding.tinkerforge') if os.path.isdir(binding_dir): print( "Binding directory exists from last run, skipping clone of openhab2-addons repo." ) with common.ChangedDirectory( os.path.join(self.get_bindings_dir(), '..', 'openhab2-addons')): common.execute(['git', 'stash']) with common.ChangedDirectory( os.path.join(self.get_bindings_dir(), '..', 'openhab2-addons')): common.execute(['git', 'pull']) with common.ChangedDirectory( os.path.join(self.get_bindings_dir(), '..', 'openhab2-addons')): common.execute(['git', 'stash', 'pop']) else: with common.ChangedDirectory( os.path.join(self.get_bindings_dir(), '..')): common.execute([ 'git', 'clone', '-b', '2.5.x', 'https://github.com/openhab/openhab2-addons', '--depth=1' ]) to_patch = os.path.join(self.get_bindings_dir(), '..', 'openhab2-addons', 'bom', 'openhab-addons', 'pom.xml') common.specialize_template( to_patch, to_patch, { '</dependencies>': """ <dependency> <groupId>org.openhab.addons.bundles</groupId> <artifactId>org.openhab.binding.tinkerforge</artifactId> <version>${project.version}</version> </dependency> </dependencies>""" }) to_patch = os.path.join(self.get_bindings_dir(), '..', 'openhab2-addons', 'bundles', 'pom.xml') common.specialize_template( to_patch, to_patch, { '</modules>': """ <module>org.openhab.binding.tinkerforge</module> </modules>""" }) common.recreate_dir(binding_dir) for f in [ k for (k, v) in self.relative_file_dests.items() if v == '.' ]: shutil.copy(os.path.join(self.generation_dir, f), os.path.join(binding_dir, f)) shutil.copytree(os.path.join(self.generation_dir, 'src'), os.path.join(binding_dir, 'src')) with common.ChangedDirectory(binding_dir): common.execute([ 'mvn', 'spotless:apply', '-Dorg.slf4j.simpleLogger.defaultLogLevel=WARN' ]) common.execute([ 'mvn', 'clean', 'install', '-Dorg.slf4j.simpleLogger.defaultLogLevel=WARN' ]) # Beta stuff zip_dir = os.path.join(self.tmp_dir, 'zip') os.makedirs(zip_dir) for f in ['changelog.txt', 'readme_de.txt', 'readme_en.txt']: shutil.copy(os.path.join(self.get_bindings_dir(), '..', 'beta', f), zip_dir) shutil.copytree( os.path.join(binding_dir, 'src'), os.path.join(zip_dir, 'org.openhab.binding.tinkerforge', 'src')) shutil.copy( os.path.join(binding_dir, 'target', 'org.openhab.binding.tinkerforge-2.5.9-SNAPSHOT.jar'), zip_dir) java_bindings = os.path.join(self.get_root_dir(), 'tinkerforge-2.1.26.jar') if not os.path.exists(java_bindings): try: from urllib.request import urlretrieve downloaded_file, _ = urlretrieve( 'https://search.maven.org/remotecontent?filepath=com/tinkerforge/tinkerforge/2.1.26/tinkerforge-2.1.26.jar' ) shutil.copy(downloaded_file, java_bindings) except Exception as e: raise common.GeneratorError( "Failed to download java bindings.") from e shutil.copy(java_bindings, zip_dir) self.create_zip_file(zip_dir)
def test(self, cookie, path, extra): uses_libgd = False with open(path, 'r') as f: uses_libgd = '#include <gd.h>' in f.read() # skip OLED scribble example because mingw32 has no libgd package if self.compiler.startswith('mingw32-') and uses_libgd: self.handle_result(cookie, 0, '>>> skipping') return if extra: shutil.copy(path, '/tmp/tester/c') path = os.path.join('/tmp/tester/c', os.path.split(path)[1]) output = path[:-2] if not extra and '/brick' in path: dirname = os.path.split(path)[0] device = '/tmp/tester/c/source/{0}_{1}.c'.format( os.path.split(os.path.split(dirname)[0])[-1], os.path.split(dirname)[-1]) else: device = '' args = [] if self.compiler == 'gcc': args += ['gcc', '-std=c99', '-pthread'] elif self.compiler == 'g++': args += ['g++', '-std=c++98', '-pthread'] elif self.compiler == 'mingw32-gcc': args += ['x86_64-w64-mingw32-gcc', '-Wno-error=return-type'] elif self.compiler == 'mingw32-g++': args += ['x86_64-w64-mingw32-g++', '-Wno-error=return-type'] elif self.compiler == 'clang': args += ['clang', '-std=c99', '-pthread'] elif self.compiler == 'scan-build clang': args += ['scan-build', 'clang', '-std=c99', '-pthread'] else: raise common.GeneratorError('Invalid compiler ' + self.compiler) args += [ '-Wall', '-Wextra', '-Werror', '-O2', '-I/tmp/tester/c/source', '-o', output, '/tmp/tester/c/source/ip_connection.c' ] if len(device) > 0: args.append(device) elif extra: dependencies = glob.glob('/tmp/tester/c/source/*.c') dependencies.remove('/tmp/tester/c/source/ip_connection.c') args.append('-Wno-error=unused-parameter') args += dependencies args.append(path) if self.compiler.startswith('mingw32-'): args += ['-lws2_32'] if uses_libgd: args += ['-lm', '-lgd'] self.execute(cookie, args)