-
Notifications
You must be signed in to change notification settings - Fork 311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
switch_tplg: Implement tool for switching topologies #9525
Draft
AnneOnciulescu
wants to merge
1
commit into
thesofproject:main
Choose a base branch
from
AnneOnciulescu:switch_tplg
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
## Topology Switch Tool | ||
|
||
### switch_tplg.py switch_tplg.sh | ||
This tool allows switching to a different topology without rebooting the board. | ||
|
||
### How to use the tool | ||
Copy both switch_tplg.py and switch_tplg.sh to the target hardware, ensuring they are in the same directory. | ||
|
||
To start the UI, run the following command on the board: | ||
```python3 switch_tplg.py``` | ||
|
||
After selecting the topology, applying it will remove and reload the relevant kernel modules, allowing the new topology to take effect without requiring a reboot. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import os | ||
import argparse | ||
import curses | ||
import subprocess | ||
|
||
os.chdir(os.path.dirname(os.path.abspath(__file__))) | ||
|
||
class TopologySelectorUI: | ||
|
||
def __init__(self, tplg_path): | ||
self.selected_tplg_file = None | ||
self.tplg_path = tplg_path | ||
self.tplg_files = self.scan_for_files('', '.tplg', extra_paths=[tplg_path]) | ||
self.tplg_files.sort() | ||
if self.tplg_files: | ||
self.selected_tplg_file = self.tplg_files[0] | ||
self.run_ui() | ||
|
||
def scan_for_files(self, directory_name: str, file_extension: str, extra_paths: list = None): | ||
found_files = [] | ||
dir_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), directory_name) | ||
|
||
if os.path.exists(dir_path): | ||
found_files.extend([f for f in os.listdir(dir_path) if f.endswith(file_extension)]) | ||
else: | ||
print(f"Error: The '{directory_name}' directory is missing. It should be located in the same folder as this script.") | ||
|
||
if extra_paths: | ||
for path in extra_paths: | ||
if os.path.exists(path): | ||
found_files.extend([f for f in os.listdir(path) if f.endswith(file_extension)]) | ||
else: | ||
print(f"Warning: The directory '{path}' does not exist.") | ||
|
||
return found_files | ||
|
||
def run_ui(self): | ||
curses.wrapper(self.main_menu) | ||
|
||
def main_menu(self, stdscr): | ||
curses.start_color() | ||
self.initialize_colors() | ||
stdscr.bkgd(' ', curses.color_pair(2)) | ||
|
||
current_row = 0 | ||
max_row = 3 | ||
|
||
while True: | ||
stdscr.clear() | ||
self.display_menu(stdscr, current_row) | ||
key = stdscr.getch() | ||
|
||
if key == curses.KEY_UP: | ||
current_row = (current_row - 1) % (max_row + 1) | ||
elif key == curses.KEY_DOWN: | ||
current_row = (current_row + 1) % (max_row + 1) | ||
|
||
actions = { | ||
0: lambda: self.select_tplg_file(stdscr), | ||
1: lambda: self.switch_topology(self.selected_tplg_file), | ||
2: lambda: exit() | ||
} | ||
|
||
if key == 10: | ||
if current_row in actions: | ||
actions[current_row]() | ||
elif current_row == 3: | ||
break | ||
|
||
def initialize_colors(self): | ||
curses.init_pair(1, curses.COLOR_BLACK, 7) | ||
curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLUE) | ||
|
||
def display_menu(self, stdscr, current_row): | ||
stdscr.addstr(0, 0, "---------------Topology Selector----------------", curses.A_BOLD) | ||
stdscr.addstr(1, 0, "================================================") | ||
|
||
menu = [ | ||
f"| Select Topology (Currently: {self.selected_tplg_file})", | ||
"| Apply Selected Topology", | ||
"| Quit " | ||
] | ||
|
||
for idx, item in enumerate(menu): | ||
color_pair = curses.color_pair(1) if idx == current_row else curses.color_pair(2) | ||
stdscr.addstr(idx + 3, 0, item, color_pair) | ||
|
||
stdscr.refresh() | ||
|
||
def select_tplg_file(self, stdscr): | ||
self.select_file_from_list(stdscr, self.tplg_files, "-----Select Topology-----") | ||
|
||
|
||
def select_file_from_list(self, stdscr, file_list, title): | ||
current_row = 0 | ||
offset = 0 | ||
max_visible_rows = curses.LINES - 2 | ||
|
||
while True: | ||
stdscr.clear() | ||
stdscr.addstr(0, 0, title, curses.A_BOLD) | ||
|
||
visible_rows = min(max_visible_rows, len(file_list)) | ||
|
||
for idx in range(visible_rows): | ||
file_idx = idx + offset | ||
if file_idx >= len(file_list): | ||
break | ||
file_name = file_list[file_idx] | ||
color_pair = curses.color_pair(1) if file_idx == current_row else curses.color_pair(2) | ||
stdscr.addstr(idx + 1, 0, file_name, color_pair) | ||
|
||
stdscr.refresh() | ||
key = stdscr.getch() | ||
|
||
if key == curses.KEY_UP: | ||
if current_row > 0: | ||
current_row -= 1 | ||
if current_row < offset: | ||
offset -= 1 | ||
elif key == curses.KEY_DOWN: | ||
if current_row < len(file_list) - 1: | ||
current_row += 1 | ||
if current_row >= offset + visible_rows: | ||
offset += 1 | ||
elif key == curses.KEY_ENTER or key in [10, 13]: | ||
self.selected_tplg_file = file_list[current_row] | ||
self.switch_topology(self.selected_tplg_file) | ||
break | ||
|
||
def switch_topology(self, tplg_file): | ||
tplg_full_path = os.path.join(self.tplg_path, tplg_file) | ||
subprocess.run(['./switch_tplg.sh', tplg_full_path], check=True) | ||
print(f"Switched to topology: {tplg_full_path}") | ||
|
||
def main(): | ||
parser = argparse.ArgumentParser(description="Topology Selector") | ||
parser.add_argument('--tplg-path', default='/lib/firmware/imx/sof-tplg', help="Path to search for topology files (.tplg)") | ||
args = parser.parse_args() | ||
|
||
TopologySelectorUI(tplg_path=args.tplg_path) | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#!/bin/sh | ||
|
||
selected_tplg=$1 | ||
target_tplg="/lib/firmware/imx/sof-tplg/sof-imx8-wm8960.tplg" | ||
|
||
cp "$target_tplg" /lib/firmware/imx/sof-tplg/previous-topology.tplg | ||
|
||
rmmod snd_sof_imx8 | ||
rmmod snd_sof_xtensa_dsp | ||
rmmod snd_sof_of | ||
rmmod imx_common | ||
rmmod snd_sof | ||
rmmod snd_sof_utils | ||
rmmod snd_soc_wm8960 | ||
rmmod snd_soc_simple_card | ||
|
||
cp "$selected_tplg" "$target_tplg" | ||
|
||
modprobe snd_soc_simple_card | ||
modprobe snd_soc_wm8960 | ||
modprobe snd_sof_utils | ||
modprobe snd_sof | ||
modprobe imx_common | ||
modprobe snd_sof_of | ||
modprobe snd_sof_xtensa_dsp | ||
modprobe snd_sof_imx8 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a prefix to the commit subject like
tools:
. Also add some implementations detail in the commit message.Like for example: we remove and then insert back all SOF related modules thus triggering topology reload.
As a development tool I think this is super useful. On the longer term I wonder if we can have this functionality in the SOF Linux driver.
Cc: @lgirdwood @ranj063
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dbaluta @AnneOnciulescu would it make sense to update the sof-insert/sof-remove scripts in the sof-test repo to do what you're suggesting? https://github.com/thesofproject/sof-test/tree/main/tools/kmod
And as for choosing a different topology should be just a simple command to se the kernel module params to choose the new topology isnt it? Can you please elaborate the need of the python tool for choosing a different topology?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be yes, but then the user needs to run 3 scripts instead of selecting the topology from a GUI. On the other hand we can create a wrapper over existing sof-insert / sof-remove scripts.
Let me talk to @AnneOnciulescu and get back with a imporved solution.
The GUI offers you a list of topology to use. That is the nicest part. Lets see though if it worth the effort.