def get_actuator_output_params(yaml_config, output_functions, timer_config_file, verbose): """ parse the actuator_output section from the yaml config file :return: dict of param definitions """ if not 'actuator_output' in yaml_config: return {} output_groups = yaml_config['actuator_output']['output_groups'] all_params = {} group_idx = 0 def add_local_param(param_name, param_def): nonlocal all_params # add as a list, as there can be multiple entries with the same param_name if not param_name in all_params: all_params[param_name] = [] all_params[param_name].append(param_def) while group_idx < len(output_groups): group = output_groups[group_idx] group_idx += 1 if verbose: print("processing group: {:}".format(group)) # Check for generator and generate additional data. # We do this by extending the output_groups list and parse in a later iteration if 'generator' in group: if group['generator'] == 'pwm': param_prefix = process_param_prefix(group['param_prefix']) channel_labels = [ process_channel_label(label) for label in group['channel_labels'] ] standard_params = group.get('standard_params', []) extra_function_groups = group.get('extra_function_groups', []) pwm_timer_param = group.get('pwm_timer_param', None) if 'timer_config_file' in group: timer_config_file = os.path.join( root_dir, group['timer_config_file']) if timer_config_file is None: raise Exception( 'trying to generate pwm outputs, but --timer-config not set' ) timer_groups = get_timer_groups(timer_config_file, verbose) timer_output_groups, timer_params = get_output_groups( timer_groups, param_prefix, channel_labels, standard_params, extra_function_groups, pwm_timer_param, verbose=verbose) all_params.update(timer_params) output_groups.extend(timer_output_groups) else: raise Exception('unknown generator {:}'.format( group['generator'])) continue num_channels = group['num_channels'] param_prefix = process_param_prefix(group['param_prefix']) channel_label = process_channel_label(group['channel_label']) standard_params = group.get('standard_params', {}) instance_start = group.get('instance_start', 1) instance_start_label = group.get('instance_start_label', instance_start) if len(param_prefix) > 9: # 16 - len('_FAIL') - 2 (2 digits for index) raise Exception("param prefix {:} too long (max length=10)".format( param_prefix)) # collect the functions function_groups = ['common'] function_groups.extend(group.get('extra_function_groups', [])) output_function_values = {} for function_group in function_groups: group = output_functions[function_group] for function_name in group: function_name_label = function_name.replace('_', ' ') if isinstance(group[function_name], int): output_function_values[ group[function_name]] = function_name_label else: start = group[function_name]['start'] count = group[function_name]['count'] for i in range(count): output_function_values[ start + i] = function_name_label + ' ' + str(i + 1) # function param param = { 'description': { 'short': channel_label + ' ${i} Output Function', 'long': '''Select what should be output on {:} ${{i}}. The default failsafe value is set according to the selected function: - 'Min' for ConstantMin - 'Max' for ConstantMax - 'Max' for Parachute - ('Max'+'Min')/2 for Servos - 'Disarmed' for the rest '''.format(channel_label), }, 'type': 'enum', 'instance_start': instance_start, 'instance_start_label': instance_start_label, 'num_instances': num_channels, 'default': 0, 'values': output_function_values } add_local_param(param_prefix + '_FUNC${i}', param) # handle standard_params disarmed_description = \ '''This is the output value that is set when not armed. Note that non-motor outputs might already be active in prearm state if COM_PREARM_MODE is set. ''' minimum_description = \ '''Minimum output value (when not disarmed). The output range can be reversed by setting Min > Max. ''' maximum_description = \ '''Maxmimum output value (when not disarmed). The output range can be reversed by setting Min > Max. ''' failsafe_description = \ '''This is the output value that is set when in failsafe mode. When set to -1 (default), the value depends on the function (see {:}). '''.format(param_prefix+'_FUNC${i}') standard_params_array = [ ('disarmed', 'Disarmed', 'DIS', disarmed_description), ('min', 'Minimum', 'MIN', minimum_description), ('max', 'Maximum', 'MAX', maximum_description), ('failsafe', 'Failsafe', 'FAIL', failsafe_description), ] for key, label, param_suffix, description in standard_params_array: if key in standard_params: # values must be in range of an uint16_t if standard_params[key]['min'] < 0: raise Exception( 'minimum value for {:} expected >= 0 (got {:})'.format( key, standard_params[key]['min'])) if standard_params[key]['max'] >= 1 << 16: raise Exception( 'maximum value for {:} expected <= {:} (got {:})'. format(key, 1 << 16, standard_params[key]['max'])) if key == 'failsafe': standard_params[key]['default'] = -1 standard_params[key]['min'] = -1 param = { 'description': { 'short': channel_label + ' ${i} ' + label + ' Value', 'long': description }, 'type': 'int32', 'instance_start': instance_start, 'instance_start_label': instance_start_label, 'num_instances': num_channels, 'min': standard_params[key]['min'], 'max': standard_params[key]['max'], 'default': standard_params[key]['default'], } add_local_param(param_prefix + '_' + param_suffix + '${i}', param) if verbose: print('adding actuator params: {:}'.format(all_params)) return all_params
def get_actuator_output(yaml_config, output_functions, timer_config_file, verbose): """ parse the actuator_output section from the yaml config file """ if not 'actuator_output' in yaml_config: return None actuator_output_yaml = yaml_config['actuator_output'] output_groups = actuator_output_yaml['output_groups'] module_name = process_module_name(yaml_config['module_name']) group_idx = 0 if verbose: print('processing module: {}'.format(module_name)) actuator_output = {'label': module_name} if 'show_subgroups_if' in actuator_output_yaml: actuator_output['show-subgroups-if'] = actuator_output_yaml[ 'show_subgroups_if'] # config parameters def get_config_params(param_list): """ convert config parameter list (per group or per subgroup) """ parameters = [] for config_param in param_list: if verbose: print('config param: {}'.format(config_param)) param = { 'name': config_param['param'], } if 'label' in config_param: param['label'] = config_param['label'] if 'function' in config_param: param['function'] = config_param['function'] parameters.append(param) return parameters parameters = get_config_params( actuator_output_yaml.get('config_parameters', [])) if len(parameters) > 0: actuator_output['parameters'] = parameters subgroups = [] while group_idx < len(output_groups): group = output_groups[group_idx] group_idx += 1 if verbose: print("processing group: {:}".format(group)) # Check for generator and generate additional data. if 'generator' in group: if group['generator'] == 'pwm': param_prefix = process_param_prefix(group['param_prefix']) no_prefix = not group.get('channel_label_module_name_prefix', True) channel_labels = [ process_channel_label(module_name, label, no_prefix) for label in group['channel_labels'] ] standard_params = group.get('standard_params', []) extra_function_groups = group.get('extra_function_groups', []) pwm_timer_param = group.get('pwm_timer_param', None) if 'timer_config_file' in group: timer_config_file = os.path.join( root_dir, group['timer_config_file']) if timer_config_file is None: raise Exception( 'trying to generate pwm outputs, but --timer-config not set' ) timer_groups = get_timer_groups(timer_config_file, verbose) timer_output_groups, timer_params = get_output_groups( timer_groups, param_prefix, channel_labels, standard_params, extra_function_groups, pwm_timer_param, verbose=verbose) output_groups.extend(timer_output_groups) else: raise Exception('unknown generator {:}'.format( group['generator'])) continue subgroup = {} # supported actions if 'supported_actions' in group: actions = {} for action_name in group['supported_actions']: action = group['supported_actions'][action_name] action_name = action_name.replace('_', '-') actions[action_name] = {} if 'supported_if' in action: actions[action_name]['supported-if'] = action[ 'supported_if'] if 'actuator_types' in action: actions[action_name]['actuator-types'] = action[ 'actuator_types'] subgroup['supported-actions'] = actions # channels num_channels = group['num_channels'] no_prefix = not group.get('channel_label_module_name_prefix', True) channel_label = process_channel_label(module_name, group['channel_label'], no_prefix) instance_start = group.get('instance_start', 1) instance_start_label = group.get('instance_start_label', instance_start) channels = [] for channel in range(num_channels): channels.append({ 'label': channel_label + ' ' + str(channel + instance_start_label), 'param-index': channel + instance_start }) subgroup['channels'] = channels if 'group_label' in group: subgroup['label'] = group['group_label'] # per-channel-params per_channel_params = [] param_prefix = process_param_prefix(group['param_prefix']) standard_params = group.get('standard_params', {}) standard_params_array = [ ('function', 'Function', 'FUNC', False), ('disarmed', 'Disarmed', 'DIS', False), ('min', 'Minimum', 'MIN', False), ('max', 'Maximum', 'MAX', False), ('failsafe', 'Failsafe', 'FAIL', True), ] for key, label, param_suffix, advanced in standard_params_array: show_if = None if key in standard_params and 'show_if' in standard_params[key]: show_if = standard_params[key]['show_if'] if key in standard_params or key == 'function': param = { 'label': label, 'name': param_prefix + '_' + param_suffix + '${i}', 'function': key, } if advanced: param['advanced'] = True if show_if: param['show-if'] = show_if per_channel_params.append(param) param = { 'label': 'Rev Range\n(for Servos)', 'name': param_prefix + '_REV', 'index-offset': -1, 'show-as': 'bitset', } per_channel_params.append(param) # TODO: support non-standard per-channel parameters subgroup['per-channel-parameters'] = per_channel_params # group config params parameters = get_config_params(group.get('config_parameters', [])) if len(parameters) > 0: subgroup['parameters'] = parameters subgroups.append(subgroup) actuator_output['subgroups'] = subgroups return actuator_output