예제 #1
0
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