From 0952b96f04ea42d866369656a4559b5905ada771 Mon Sep 17 00:00:00 2001 From: Amery Song Date: Wed, 21 Oct 2020 10:23:11 +0800 Subject: [PATCH 1/6] tools: move shared python functions to common.py No functional change, only move code here and there, and add some comment. Signed-off-by: Amery Song --- tools/common.py | 30 ++++++++++++++++++++++++++++++ tools/sof-tplgreader.py | 28 +--------------------------- 2 files changed, 31 insertions(+), 27 deletions(-) create mode 100755 tools/common.py diff --git a/tools/common.py b/tools/common.py new file mode 100755 index 00000000..1dd62679 --- /dev/null +++ b/tools/common.py @@ -0,0 +1,30 @@ +def func_dump_pipeline(pipeline, noKey=False): + output = "" + for key, value in pipeline.items(): + if noKey is True: + output += str(value) + " " + else: + output += key + "=" + str(value) + ";" + return output.strip() + +# This function will generate shell code according to pipeline parameters, +# then pipeline parameters can be accessed from test case by sourcing or +# executing the generated code. +def func_export_pipeline(pipeline_lst): + length = len(pipeline_lst) + keyword = 'PIPELINE' + # clear up the older define + print('unset %s_COUNT' % (keyword)) + print('unset %s_LST' % (keyword)) + print('declare -g %s_COUNT' % (keyword)) + print('declare -ag %s_LST' % (keyword)) + print('%s_COUNT=%d' % (keyword, length)) + for idx in range(0, length): + # store pipeline + print('%s_LST[%d]="%s"' % (keyword, idx, func_dump_pipeline(pipeline_lst[idx]))) + # store pipeline to each list + print('unset %s_%d' % (keyword, idx)) + print('declare -Ag %s_%d' % (keyword, idx)) + for key, value in pipeline_lst[idx].items(): + print('%s_%d["%s"]="%s"' % (keyword, idx, key, value)) + return 0 diff --git a/tools/sof-tplgreader.py b/tools/sof-tplgreader.py index c84d170e..c4df38bc 100755 --- a/tools/sof-tplgreader.py +++ b/tools/sof-tplgreader.py @@ -4,6 +4,7 @@ import os import re from tplgtool import TplgParser, TplgFormatter +from common import func_dump_pipeline, func_export_pipeline class clsTPLGReader: def __init__(self): @@ -243,33 +244,6 @@ def getPipeline(self, sort=False): return self._output_lst if __name__ == "__main__": - def func_dump_pipeline(pipeline, noKey=False): - output = "" - for key, value in pipeline.items(): - if noKey is True: - output += str(value) + " " - else: - output += key + "=" + str(value) + ";" - return output.strip() - - def func_export_pipeline(pipeline_lst): - length = len(pipeline_lst) - keyword = 'PIPELINE' - # clear up the older define - print('unset %s_COUNT' % (keyword)) - print('unset %s_LST' % (keyword)) - print('declare -g %s_COUNT' % (keyword)) - print('declare -ag %s_LST' % (keyword)) - print('%s_COUNT=%d' % (keyword, length)) - for idx in range(0, length): - # store pipeline - print('%s_LST[%d]="%s"' % (keyword, idx, func_dump_pipeline(pipeline_lst[idx]))) - # store pipeline to each list - print('unset %s_%d' % (keyword, idx)) - print('declare -Ag %s_%d' % (keyword, idx)) - for key, value in pipeline_lst[idx].items(): - print('%s_%d["%s"]="%s"' % (keyword, idx, key, value)) - return 0 def func_getPipeline(tplgObj, tplgName, sdcard_id, sort): if tplgObj.loadFile(tplgName, sdcard_id) != 0: From 796de4875ddb4030aa7fca9601432e3e6209ca7b Mon Sep 17 00:00:00 2001 From: Amery Song Date: Fri, 23 Oct 2020 13:15:10 +0800 Subject: [PATCH 2/6] tools: rename func_dump_pipeline and func_export_pipeline This patch renames func_dump_pipeline to format_pipeline, and renames func_export_pipeline to export_pipeline. Signed-off-by: Amery Song --- tools/common.py | 6 +++--- tools/sof-tplgreader.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/common.py b/tools/common.py index 1dd62679..09f53f07 100755 --- a/tools/common.py +++ b/tools/common.py @@ -1,4 +1,4 @@ -def func_dump_pipeline(pipeline, noKey=False): +def format_pipeline(pipeline, noKey=False): output = "" for key, value in pipeline.items(): if noKey is True: @@ -10,7 +10,7 @@ def func_dump_pipeline(pipeline, noKey=False): # This function will generate shell code according to pipeline parameters, # then pipeline parameters can be accessed from test case by sourcing or # executing the generated code. -def func_export_pipeline(pipeline_lst): +def export_pipeline(pipeline_lst): length = len(pipeline_lst) keyword = 'PIPELINE' # clear up the older define @@ -21,7 +21,7 @@ def func_export_pipeline(pipeline_lst): print('%s_COUNT=%d' % (keyword, length)) for idx in range(0, length): # store pipeline - print('%s_LST[%d]="%s"' % (keyword, idx, func_dump_pipeline(pipeline_lst[idx]))) + print('%s_LST[%d]="%s"' % (keyword, idx, format_pipeline(pipeline_lst[idx]))) # store pipeline to each list print('unset %s_%d' % (keyword, idx)) print('declare -Ag %s_%d' % (keyword, idx)) diff --git a/tools/sof-tplgreader.py b/tools/sof-tplgreader.py index c4df38bc..de6852fe 100755 --- a/tools/sof-tplgreader.py +++ b/tools/sof-tplgreader.py @@ -4,7 +4,7 @@ import os import re from tplgtool import TplgParser, TplgFormatter -from common import func_dump_pipeline, func_export_pipeline +from common import format_pipeline, export_pipeline class clsTPLGReader: def __init__(self): @@ -350,7 +350,7 @@ def parse_and_set_block_keyword(block_str, tplgreader): pipeline_lst += func_getPipeline(tplgreader, f, ret_args['sofcard'], ret_args['sort'])[:] if ret_args['export'] is True: - exit(func_export_pipeline(pipeline_lst)) + exit(export_pipeline(pipeline_lst)) if ret_args['count'] is True: if ret_args['value'] is True: @@ -358,7 +358,7 @@ def parse_and_set_block_keyword(block_str, tplgreader): else: print("Pipeline Count: %d" % (len(pipeline_lst))) elif ret_args['index'] is not None and ret_args['index'] < len(pipeline_lst): - print(func_dump_pipeline(pipeline_lst[ret_args['index']], ret_args['value'])) + print(format_pipeline(pipeline_lst[ret_args['index']], ret_args['value'])) else: for pipeline in pipeline_lst: - print(func_dump_pipeline(pipeline, ret_args['value'])) + print(format_pipeline(pipeline, ret_args['value'])) From d1210f7563ce921c59780e958e508990e89e806e Mon Sep 17 00:00:00 2001 From: Amery Song Date: Wed, 21 Oct 2020 10:48:10 +0800 Subject: [PATCH 3/6] sof-dump-status: dump pipeline info from proc for legacy HDA To reuse test cases from sof-test repo, we need to dump pipeline info from proc, just like dump pipeline info from topology on SOF platform. As there is no format/channel/rate information in proc, we hard code some default format/channel/rate values, this should be enough for legacy HDA platform test. Signed-off-by: Amery Song --- tools/sof-dump-status.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tools/sof-dump-status.py b/tools/sof-dump-status.py index 1075804a..6d28d67a 100755 --- a/tools/sof-dump-status.py +++ b/tools/sof-dump-status.py @@ -2,6 +2,7 @@ import subprocess import os +from common import format_pipeline, export_pipeline class clsSYSCardInfo(): def __init__(self): @@ -364,12 +365,8 @@ def export_proc_sound(proc_card): return def dump_cardinfo_pcm(card_info): - pcm_lst = card_info.get('pcm') - def _getStr(tmp_dict, key): - return '%s=%s'%(key, tmp_dict.get(key)) - for pcm in pcm_lst: - print('%s;%s;%s;' % (_getStr(pcm, 'id'), _getStr(pcm, 'pcm'), _getStr(pcm, 'type'))) - return 0 + for pipeline in card_info.get('pcm'): + print(format_pipeline(pipeline)) def dump_dapm(dapm, filter = "all"): if filter == "all" and len(dapm['dapm_lst']) == 0: @@ -413,6 +410,7 @@ def dump_dapm(dapm, filter = "all"): parser.add_argument('-P', '--fwpath', action='store_true', help='get firmware path according to DMI info') parser.add_argument('-S', '--dsp_status', type=int, help='get current dsp power status, should specify sof card number') parser.add_argument('-d', '--dapm', choices=['all', 'on', 'off', 'standby'], help='get current dapm status, this option need root permission to access debugfs') + parser.add_argument('-e', '--export', action='store_true', help='export pipeline parameters from proc file system') parser.add_argument('--version', action='version', version='%(prog)s 1.0') ret_args = vars(parser.parse_args()) @@ -437,6 +435,22 @@ def dump_dapm(dapm, filter = "all"): print(run_status['status']) exit(0) + if ret_args['export'] is True: + sysinfo.loadProcSound() + pipeline_lst = [] + for (card_id, card_info) in sysinfo.proc_card.items(): + for pcm in card_info['pcm']: + # There are limited pipeline parameters in the proc file system, + # add some default parameters to make use of sof-test for legacy HDA test + pcm['fmt'] = 'S16_LE' + pcm['fmts'] = 'S16_LE S24_LE S32_LE' + pcm['rate'] = '48000' + pcm['channel'] = '2' + pcm['dev'] = 'hw:{},{}'.format(card_id, pcm['id']) + pipeline_lst.extend(card_info['pcm']) + export_pipeline(pipeline_lst) + exit(0) + if ret_args.get('id') is not None: sysinfo.loadProcSound() card_info = sysinfo.proc_card.get(str(ret_args['id'])) From 2f9eb1b5a4012affb86f6d609d18b076962f996d Mon Sep 17 00:00:00 2001 From: Amery Song Date: Thu, 22 Oct 2020 17:49:47 +0800 Subject: [PATCH 4/6] sof-dump-status: add a type filter for proc pipeline We don't need a complex filter for proc pipeline as topology pipeline does. So a simple type filter for proc pipeline is implemented in this patch. This makes it possible for some test cases to run under legacy HDA platform without any script change. Signed-off-by: Amery Song --- tools/sof-dump-status.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/tools/sof-dump-status.py b/tools/sof-dump-status.py index 6d28d67a..1b61dbed 100755 --- a/tools/sof-dump-status.py +++ b/tools/sof-dump-status.py @@ -410,7 +410,11 @@ def dump_dapm(dapm, filter = "all"): parser.add_argument('-P', '--fwpath', action='store_true', help='get firmware path according to DMI info') parser.add_argument('-S', '--dsp_status', type=int, help='get current dsp power status, should specify sof card number') parser.add_argument('-d', '--dapm', choices=['all', 'on', 'off', 'standby'], help='get current dapm status, this option need root permission to access debugfs') - parser.add_argument('-e', '--export', action='store_true', help='export pipeline parameters from proc file system') + # The filter string here is compatible with the filter string for pipeline from topology, + # and takes the form of 'type:playback & pga:any & ~asrc:any | id:5'. + parser.add_argument('-e', '--export', type=str, help='export pipeline parameters of specified type from proc file system,\n' + 'to specify pipeline type, use "-e type:playback", complex string like\n' + '"type:playback & pga:any" can be used, but only "type" is processed') parser.add_argument('--version', action='version', version='%(prog)s 1.0') ret_args = vars(parser.parse_args()) @@ -435,7 +439,7 @@ def dump_dapm(dapm, filter = "all"): print(run_status['status']) exit(0) - if ret_args['export'] is True: + if ret_args['export'] is not None: sysinfo.loadProcSound() pipeline_lst = [] for (card_id, card_info) in sysinfo.proc_card.items(): @@ -448,7 +452,26 @@ def dump_dapm(dapm, filter = "all"): pcm['channel'] = '2' pcm['dev'] = 'hw:{},{}'.format(card_id, pcm['id']) pipeline_lst.extend(card_info['pcm']) - export_pipeline(pipeline_lst) + # The filter string may be very complex due to the compatibility with topology pipeline + # filter string, but we only implement a simple type filter here. + try: + # ret_args['export'] contains filter string, and it may looks like 'type:capture & pga:any | id:3' + # extract filter elements, and drop logic operator + filter_elements = [elem for elem in ret_args['export'].split(' ') if ':' in elem] + # extract requested pipeline type from filter elements, and ignore others. + requested_type = [f.split(':')[1] for f in filter_elements if f.strip().startswith('type')][0] + except: + print('Invalid filter string') + exit(1) + # requested_type may take one of the values: playback, capture, any + if requested_type in ['playback', 'capture']: + export_pipeline([p for p in pipeline_lst if p['type'] == requested_type]) + elif requested_type == 'any': + export_pipeline(pipeline_lst) + else: + print('Unknown requested pipeline type: %s' % requested_type) + print('Available requested pipeline types are: playback, capture, any') + exit(1) exit(0) if ret_args.get('id') is not None: From 7af5c7ce241acc52282bf1b9feccf273c0a820af Mon Sep 17 00:00:00 2001 From: Amery Song Date: Wed, 21 Oct 2020 10:55:04 +0800 Subject: [PATCH 5/6] lib.sh: add is_sof_used function This patch adds is_sof_used function to check we are running test on SOF platform or legacy HDA platform. Signed-off-by: Amery Song --- case-lib/lib.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/case-lib/lib.sh b/case-lib/lib.sh index de53bc2c..cb81387a 100644 --- a/case-lib/lib.sh +++ b/case-lib/lib.sh @@ -264,3 +264,8 @@ sudo sync -f || true if [ ! "$DMESG_LOG_START_LINE" ]; then DMESG_LOG_START_LINE=$(wc -l /var/log/kern.log|awk '{print $1;}') fi + +is_sof_used() +{ + grep -q "sof" /proc/asound/cards; +} From f0314fa708690fd25c0ceb5705f3222b8e973dba Mon Sep 17 00:00:00 2001 From: Amery Song Date: Wed, 21 Oct 2020 10:56:22 +0800 Subject: [PATCH 6/6] pipeline.sh: export proc pipeline info to test case Signed-off-by: Amery Song --- case-lib/pipeline.sh | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/case-lib/pipeline.sh b/case-lib/pipeline.sh index b7b11e1c..198db78b 100644 --- a/case-lib/pipeline.sh +++ b/case-lib/pipeline.sh @@ -1,11 +1,33 @@ #!/bin/bash +# This function will evaluate pipeline parameter related shell code generated by +# - sof-tplgreader.py (for SOF, pipeline parameters dumped from topology) +# - sof-dump-status.py (for legacy HDA, pipeline paramters dumped from proc) +# Args: $1: SOF topology path +# $2: Pipeline filter in string form +# Note: for legacy HDA, topology is not present, $1 will be empty. func_pipeline_export() { - # no parameter input the function - if [ $# -lt 1 ]; then - die "Topology file name is not specified, unable to run command: $SCRIPT_NAME" + + # function parameter check + if [ $# -ne 2 ]; then + die "Not enough parameters, expect two parameters: topology path and pipeline filter" fi + + # For legacy HDA platform, there is no topology, we have to export pipeline + # parameters from proc file system. + is_sof_used || { + filter_str="$2" + dlogi "No SOF sound card found, exporting pipeline parameters from proc file system" + tmp_pipeline_params=$(mktemp /tmp/pipeline-params.XXXXXXXX) + sof-dump-status.py -e "$filter_str" > "$tmp_pipeline_params" || + die "Failed to export pipeline parameters from proc file system" + # shellcheck disable=SC1090 + source "$tmp_pipeline_params" || return 1 + rm "$tmp_pipeline_params" + return 0 + } + # got tplg_file, verify file exist tplg_path=$(func_lib_get_tplg_path "$1") || { die "Topology $1 not found, check the TPLG environment variable or specify topology path with -t"