diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8e60d920f74e966bd986811c33ebc97bb8a1fd6d..e327ad33bd245b6561f3aec6dca6d6d64af4603d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -20,7 +20,7 @@ stages:
   - Build Env and Test
 before_script:
   - pip install -e .[dev]
-  - apt-get update && apt install -y libgl1-mesa-glx
+  - apt-get update && apt install -y libgl1-mesa-glx libxkbcommon-x11-0 libegl1 libdbus-1-3
 
 flake8:
   image: python:3.8
diff --git a/setup.py b/setup.py
index 339530a3b58b92191dc5402a8bd69ec0bc37adcd..d3ebbe37e3cfb977c71ff8756d45c84ef83534b4 100644
--- a/setup.py
+++ b/setup.py
@@ -32,7 +32,7 @@ setup(
         ],
     },
     install_requires=['obspy',
-                      'PySide2',
+                      'PySide6',
                       'matplotlib',
                       'numpy'],
     setup_requires=[],
diff --git a/sohstationviewer.py b/sohstationviewer.py
index 296d459799da264f4256030e321e90a299ab8a16..20ecf79e04229f98c5880ddb30c23e8d81a59096 100755
--- a/sohstationviewer.py
+++ b/sohstationviewer.py
@@ -2,27 +2,16 @@
 import platform
 import os
 import sys
-from PySide2 import QtWidgets
+from PySide6 import QtWidgets
 
 from sohstationviewer.view.main_window import MainWindow
 
 
-# Enable Layer-backing for MacOs version >= 11
-# Only needed if using the pyside2 library with version>=5.15.
-# Layer-backing is always enabled in pyside6.
-os_name, version, *_ = platform.platform().split('-')
-# if os_name == 'macOS' and version >= '11':
-# mac OSX 11.6 appear to be 10.16 when read with python and still required this
-# environment variable
-if os_name == 'macOS':
-    os.environ['QT_MAC_WANTS_LAYER'] = '1'
-
-
 def main():
     app = QtWidgets.QApplication(sys.argv)
     wnd = MainWindow()
     wnd.show()
-    sys.exit(app.exec_())
+    sys.exit(app.exec())
 
 
 if __name__ == '__main__':
diff --git a/sohstationviewer/controller/processing.py b/sohstationviewer/controller/processing.py
index d900d1c8a59f69595a08b0db476fcc8f60f11561..64c83a98680d6fd4b0585250062b4dccbf1924e0 100644
--- a/sohstationviewer/controller/processing.py
+++ b/sohstationviewer/controller/processing.py
@@ -9,9 +9,9 @@ import re
 from pathlib import Path
 from typing import List, Optional, Dict, Tuple
 
-from PySide2.QtCore import QEventLoop, Qt
-from PySide2.QtGui import QCursor
-from PySide2.QtWidgets import QTextBrowser, QApplication
+from PySide6.QtCore import QEventLoop, Qt
+from PySide6.QtGui import QCursor
+from PySide6.QtWidgets import QTextBrowser, QApplication
 from obspy.io import reftek
 from obspy import UTCDateTime
 
@@ -183,9 +183,10 @@ def detect_data_type(list_of_dir: List[str]) -> Optional[str]:
     sign_chan_data_type_dict = get_signature_channels()
 
     dir_data_type_dict = {}
-    is_multiplex = None
+    is_multiplex_dict = {}
     for d in list_of_dir:
         data_type = "Unknown"
+        is_multiplex = None
         for path, subdirs, files in os.walk(d):
             for file_name in files:
                 path2file = Path(path).joinpath(file_name)
@@ -205,10 +206,12 @@ def detect_data_type(list_of_dir: List[str]) -> Optional[str]:
         if is_multiplex is None:
             raise Exception("No channel found for the data set")
 
+        is_multiplex_dict[d] = is_multiplex
         if data_type == "Unknown":
             dir_data_type_dict[d] = "Unknown"
         else:
             dir_data_type_dict[d] = data_type
+    is_multiplex_list = list(set(is_multiplex_dict.values()))
     data_type_list = list(set(dir_data_type_dict.values()))
     if len(data_type_list) > 1:
         dir_data_type_str = json.dumps(dir_data_type_dict)
@@ -218,13 +221,17 @@ def detect_data_type(list_of_dir: List[str]) -> Optional[str]:
                f"{dir_data_type_str}\n\n"
                f"Please have only data that related to each other.")
         raise Exception(msg)
-
+    elif len(is_multiplex_list) > 1:
+        msg = ("There are both multiplexed and non-multiplexed data "
+               "detected.\n\nPlease have only data that related to"
+               " each other.")
+        raise Exception(msg)
     elif data_type_list == ['Unknown']:
         msg = ("There are no known data detected.\n\n"
                "Do you want to cancel to select different folder(s)\n"
                "Or continue to read any available mseed file?")
         raise Exception(msg)
-    return data_type_list[0], is_multiplex
+    return data_type_list[0], is_multiplex_list[0]
 
 
 def get_data_type_from_file(
diff --git a/sohstationviewer/controller/util.py b/sohstationviewer/controller/util.py
index 0e46a24ab1b673918022c15dacbacce654c11bcf..d846fd0085071d27abcc1df70cf6a1db7f712fe3 100644
--- a/sohstationviewer/controller/util.py
+++ b/sohstationviewer/controller/util.py
@@ -9,10 +9,10 @@ from datetime import datetime
 from pathlib import Path
 from typing import List, Dict
 
-from PySide2 import QtCore
+from PySide6 import QtCore
 from typing import Tuple, Union
 
-from PySide2.QtWidgets import QTextBrowser
+from PySide6.QtWidgets import QTextBrowser
 from obspy import UTCDateTime
 from sohstationviewer.view.util.enums import LogType
 
@@ -24,7 +24,6 @@ def validate_file(path2file: Union[str, Path], file_name: str):
     :param file_name: name of the file
     :return: True if pass checking, False if not.
     """
-
     if file_name.startswith('.'):
         # skip info file
         return False
@@ -312,3 +311,21 @@ def check_data_sdata(root_dir: str) -> bool:
     dir_list = [d for d in os.listdir(root_dir)
                 if os.path.isdir(os.path.join(root_dir, d))]
     return 'data' in dir_list and 'sdata' in dir_list
+
+
+def get_valid_file_count(list_of_dir: Path) -> int:
+    """
+    Get total number of valid files in valid directories from the list_of_dir
+    :param list_of_dir: list of paths to the folders of data
+    :return total: total number of valid files
+    """
+    total = 0
+    for folder in list_of_dir:
+        for path, _, files in os.walk(folder):
+            try:
+                validate_dir(path)
+            except Exception:
+                continue
+            total += len([f for f in files
+                         if validate_file(Path(path).joinpath(f), f)])
+    return total
diff --git a/sohstationviewer/database/soh.db b/sohstationviewer/database/soh.db
index 90430cd3be7ab2b25781a5f0d15c3f640e62b3a2..ad3f16f89d639912d745447ffd9203a951ee9e04 100755
Binary files a/sohstationviewer/database/soh.db and b/sohstationviewer/database/soh.db differ
diff --git a/sohstationviewer/model/data_loader.py b/sohstationviewer/model/data_loader.py
index a1bfb1a29f90cea2e3fd64e31d6cd0941a86e6df..4878728f08d64d117099b6ff8ebeba2f317ae05f 100644
--- a/sohstationviewer/model/data_loader.py
+++ b/sohstationviewer/model/data_loader.py
@@ -5,7 +5,7 @@ import traceback
 from pathlib import Path
 from typing import Union, List, Optional
 
-from PySide2 import QtCore, QtWidgets
+from PySide6 import QtCore, QtWidgets
 
 from sohstationviewer.conf import constants
 from sohstationviewer.controller.util import display_tracking_info
@@ -27,7 +27,7 @@ class DataLoaderWorker(QtCore.QObject):
 
     def __init__(self, data_type: str, tracking_box: QtWidgets.QTextBrowser,
                  is_multiplex: Optional[bool],
-                 folder: str, list_of_rt130_paths: List[Path],
+                 list_of_dir: List[Path], list_of_rt130_paths: List[Path],
                  req_wf_chans: Union[List[str], List[int]] = [],
                  req_soh_chans: List[str] = [], read_start: float = 0,
                  gap_minimum: Optional[float] = None,
@@ -38,7 +38,7 @@ class DataLoaderWorker(QtCore.QObject):
         self.data_type = data_type
         self.tracking_box = tracking_box
         self.is_multiplex = is_multiplex
-        self.folder = folder
+        self.list_of_dir = list_of_dir
         self.list_of_rt130_paths = list_of_rt130_paths
         self.req_wf_chans = req_wf_chans
         self.req_soh_chans = req_soh_chans
@@ -57,6 +57,9 @@ class DataLoaderWorker(QtCore.QObject):
         self.end_msg = None
 
     def run(self):
+        folders = (self.list_of_rt130_paths
+                   if self.list_of_dir == [''] else self.list_of_dir)
+        folders_str = ', '.join([dir.name for dir in folders])
         try:
             if self.data_type == 'RT130':
                 from sohstationviewer.model.reftek_data.reftek import RT130
@@ -71,7 +74,7 @@ class DataLoaderWorker(QtCore.QObject):
                                        type=QtCore.Qt.DirectConnection)
             data_object.__init__(
                 self.data_type, self.tracking_box,
-                self.is_multiplex, self.folder,
+                self.is_multiplex, self.list_of_dir,
                 self.list_of_rt130_paths, req_wf_chans=self.req_wf_chans,
                 req_soh_chans=self.req_soh_chans, gap_minimum=self.gap_minimum,
                 read_start=self.read_start, read_end=self.read_end,
@@ -91,11 +94,11 @@ class DataLoaderWorker(QtCore.QObject):
             self.failed.emit()
         except Exception:
             fmt = traceback.format_exc()
-            self.end_msg = (f"Dir {self.folder} can't be read "
+            self.end_msg = (f"Some in {folders_str} can't be read "
                             f"due to error: {str(fmt)}")
             self.failed.emit()
         else:
-            self.end_msg = f'Finished loading data stored in {self.folder}'
+            self.end_msg = f'Finished loading data stored in {folders_str}'
             self.finished.emit(data_object)
 
 
@@ -155,7 +158,7 @@ class DataLoader(QtCore.QObject):
             data_type,
             tracking_box,
             is_multiplex,
-            list_of_dir[0],  # Only work on one directory for now.
+            list_of_dir,
             list_of_rt130_paths,
             req_wf_chans=req_wf_chans,
             req_soh_chans=req_soh_chans,
@@ -237,7 +240,7 @@ class DataLoader(QtCore.QObject):
             )
         abort_button = msg_box.addButton(QtWidgets.QMessageBox.Abort)
 
-        msg_box.exec_()
+        msg_box.exec()
 
         if msg_box.clickedButton() == abort_button:
             # The default choice is the first item, so we default to it if the
diff --git a/sohstationviewer/model/data_type_model.py b/sohstationviewer/model/data_type_model.py
index 2f8c6a5dd21e56315dc7a9c6a6527002d3f5fd75..f10173697d2744ab31d25462da8102aab37c7aa9 100644
--- a/sohstationviewer/model/data_type_model.py
+++ b/sohstationviewer/model/data_type_model.py
@@ -7,8 +7,8 @@ from typing import Optional, Union, List, Tuple, Dict
 from obspy import UTCDateTime
 from obspy.core import Stream
 
-from PySide2 import QtCore
-from PySide2 import QtWidgets
+from PySide6 import QtCore
+from PySide6 import QtWidgets
 
 from sohstationviewer.controller.util import display_tracking_info
 from sohstationviewer.conf import constants
diff --git a/sohstationviewer/model/decimator.py b/sohstationviewer/model/decimator.py
index 7054bd8b0d1b5ccda4a48c2f575fb4c750a2025f..b9577163a3819def58da953c817eb06448c9bd59 100644
--- a/sohstationviewer/model/decimator.py
+++ b/sohstationviewer/model/decimator.py
@@ -1,4 +1,4 @@
-from PySide2 import QtCore
+from PySide6 import QtCore
 from obspy import Trace
 
 # Global flag that determines whether the user requested to stop processing and
diff --git a/sohstationviewer/model/downsampler.py b/sohstationviewer/model/downsampler.py
index 3f1e5f139f52d87385dd42bb7b176191854912c8..03bf322454cd569c85bce2f1db97c27ab48e1dff 100644
--- a/sohstationviewer/model/downsampler.py
+++ b/sohstationviewer/model/downsampler.py
@@ -4,7 +4,7 @@ This module provides access to a class that loads data in a separate thread.
 import math
 
 import numpy as np
-from PySide2 import QtCore
+from PySide6 import QtCore
 
 from sohstationviewer.conf import constants as const
 
diff --git a/sohstationviewer/model/general_data/general_data.py b/sohstationviewer/model/general_data/general_data.py
index 4e8924e0e9a4ec239e5fd10ed8e61f7c9ceb2b5a..74b25dc74790f93d710d35cdd9e13d22726222a2 100644
--- a/sohstationviewer/model/general_data/general_data.py
+++ b/sohstationviewer/model/general_data/general_data.py
@@ -1,15 +1,17 @@
 from __future__ import annotations
-
+import os
 from pathlib import Path
 from tempfile import TemporaryDirectory
 from typing import Optional, Union, List, Tuple, Dict
+import traceback
 
 from obspy import UTCDateTime
 
-from PySide2 import QtCore
-from PySide2 import QtWidgets
+from PySide6 import QtCore
+from PySide6 import QtWidgets
 
-from sohstationviewer.controller.util import display_tracking_info
+from sohstationviewer.controller.util import \
+    display_tracking_info, get_valid_file_count, validate_file, validate_dir
 from sohstationviewer.view.plotting.gps_plot.gps_point import GPSPoint
 from sohstationviewer.view.util.enums import LogType
 from sohstationviewer.database.process_db import execute_db
@@ -36,7 +38,7 @@ class ThreadStopped(Exception):
 class GeneralData():
     def __init__(self, data_type,
                  tracking_box: Optional[QtWidgets.QTextBrowser] = None,
-                 is_multiplex: bool = False, folder: str = '.',
+                 is_multiplex: bool = False, list_of_dir: List[str] = [],
                  list_of_rt130_paths: List[Path] = [],
                  req_wf_chans: Union[List[str], List[int]] = [],
                  req_soh_chans: List[str] = [],
@@ -64,7 +66,8 @@ class GeneralData():
 
         :param data_type: type of the object
         :param tracking_box: widget to display tracking info
-        :param folder: path to the folder of data
+        :param is_multiplex: flag showing if a file have more than one channel
+        :param list_of_dir: list of paths to the folders of data
         :param list_of_rt130_paths: path to the folders of RT130 data
         :param req_wf_chans: requested waveform channel list
         :param req_soh_chans: requested SOH channel list
@@ -82,9 +85,9 @@ class GeneralData():
             data loader is paused.
         """
         self.data_type = data_type
-        self.is_multiplex = is_multiplex
         self.tracking_box = tracking_box
-        self.dir = folder
+        self.is_multiplex = is_multiplex
+        self.list_of_dir = list_of_dir
         self.list_of_rt130_paths = list_of_rt130_paths
         self.req_soh_chans = req_soh_chans
         self.req_wf_chans = req_wf_chans
@@ -95,7 +98,6 @@ class GeneralData():
         self.include_mp456uvw = include_mp456uvw
         self.rt130_waveform_data_req = rt130_waveform_data_req
         self.on_unittest = on_unittest
-
         if creator_thread is None:
             err_msg = (
                 'A signal is not None while running in main thread'
@@ -158,15 +160,6 @@ class GeneralData():
 
         self.gps_points: List[GPSPoint] = []
 
-    def read_folder(self, folder: str) -> Tuple[Dict]:
-        """
-        FROM data_type_model.DataTypeModel.read_folder
-        Read data from given folder
-        :param folder: path to folder to read data
-        :return: Tuple of different data dicts
-        """
-        pass
-
     def select_key(self) -> Union[str, Tuple[str, str]]:
         """
         FROM data_type_model.DataTypeModel.select_key
@@ -182,8 +175,7 @@ class GeneralData():
 
         if self.creator_thread.isInterruptionRequested():
             raise ThreadStopped()
-        self.read_folder(self.dir)
-
+        self.read_folders()
         self.selected_key = self.select_key()
 
         self.fill_empty_data()
@@ -191,6 +183,65 @@ class GeneralData():
             raise ThreadStopped()
         self.finalize_data()
 
+    def read_folders(self, folders) -> None:
+        """
+        Read data from given folders to create data dicts which are
+            attributes of current class
+        """
+        count = 0
+        total = get_valid_file_count(folders)
+        for folder in folders:
+            count = self.read_folder(folder, total, count)
+
+    def read_folder(self, folder: str, total: int, count: int) -> int:
+        """
+        Read data from current folder.
+
+        :param folder: folder to read data from
+        :param total: total of all valid files
+        :param count: total of files that have been processed before this
+            folder to keep track of progress
+        :return count: total of files that have been processed after this
+            folder to keep track of progress
+        """
+        if not os.path.isdir(folder):
+            raise ProcessingDataError(f"Path '{folder}' not exist")
+
+        for path, sub_dirs, files in os.walk(folder):
+            try:
+                validate_dir(path)
+            except Exception as e:
+                # skip Information folder
+                self.track_info(str(e), LogType.WARNING)
+                continue
+            for file_name in files:
+                if self.creator_thread.isInterruptionRequested():
+                    raise ThreadStopped()
+
+                path2file = Path(path).joinpath(file_name)
+                if not validate_file(path2file, file_name):
+                    continue
+                count += 1
+                try:
+                    self.read_file(path2file, file_name, count, total)
+                except Exception:
+                    fmt = traceback.format_exc()
+                    self.track_info(f"Skip file {path2file} can't be read "
+                                    f"due to error: {str(fmt)}",
+                                    LogType.WARNING)
+        return count
+
+    def read_file(self, path2file: Path, file_name: str,
+                  count: int, total: int) -> None:
+        """
+        Read data or text from file
+        :param path2file: absolute path to file
+        :param file_name: name of file
+        :param count: total number of file read
+        :param total: total number of all valid files
+        """
+        pass
+
     def finalize_data(self):
         """
         CHANGED FROM data_type_model.Data_Type_Model.finalize_data
diff --git a/sohstationviewer/model/mseed_data/mseed.py b/sohstationviewer/model/mseed_data/mseed.py
index bcc61e33a4a32a965069dc700e2008b967d5e080..58acbf31c86335f095ec46dd3017a8c0e9ea4456 100644
--- a/sohstationviewer/model/mseed_data/mseed.py
+++ b/sohstationviewer/model/mseed_data/mseed.py
@@ -3,15 +3,12 @@ MSeed object to hold and process MSeed data
 """
 import os
 import re
-import traceback
 from pathlib import Path
-from typing import Dict, Tuple, List
+from typing import Dict, List
 
-from sohstationviewer.controller.util import validate_file, validate_dir
 from sohstationviewer.view.util.enums import LogType
 
-from sohstationviewer.model.general_data.general_data import \
-    GeneralData, ThreadStopped, ProcessingDataError
+from sohstationviewer.model.general_data.general_data import GeneralData
 from sohstationviewer.model.general_data.general_data_helper import read_text
 
 from sohstationviewer.model.mseed_data.mseed_helper import \
@@ -31,6 +28,8 @@ class MSeed(GeneralData):
         # FROM mseed.mseed.MSEED.__init__
         super().__init__(*args, **kwargs)
         self.nets_by_sta: Dict[str, List[str]] = {}
+        self.invalid_blockettes = False
+        self.not_mseed_files = []
         self.processing_data()
 
     def finalize_data(self):
@@ -46,83 +45,55 @@ class MSeed(GeneralData):
         self.retrieve_nets_from_data_dicts()
         super().finalize_data()
 
-    def read_folder(self, folder: str) -> Tuple[Dict]:
+    def read_folders(self) -> None:
         """
-        CHANGED FROM mseed.mseed.MSEED.read_folder
-
-        Read data streams for soh, mass position and waveform.
-
-        :param folder: absolute path to data set folder
-        :return waveform_data: waveform data by station
-        :return soh_data: soh data by station
-        :return mass_pos_data: mass position data by station
-        :return gaps: gap list by station
-        :return nets_by_sta: netcodes list by station
+        Read data from list_of_dir for soh, mass position and waveform.
         """
-        if not os.path.isdir(folder):
-            raise ProcessingDataError(f"Path '{folder}' not exist")
-        count = 0
-
-        total = sum([len(files) for _, _, files in os.walk(folder)])
-        invalid_blockettes = False
-        not_mseed_files = []
-        for path, sub_dirs, files in os.walk(folder):
-            try:
-                validate_dir(path)
-            except Exception as e:
-                # skip Information folder
-                self.track_info(str(e), LogType.WARNING)
-                continue
-            for file_name in files:
-                if self.creator_thread.isInterruptionRequested():
-                    raise ThreadStopped()
-
-                path2file = Path(path).joinpath(file_name)
-
-                if not validate_file(path2file, file_name):
-                    continue
-                count += 1
-                if count % 10 == 0:
-                    self.track_info(
-                        f'Read {count} files/{total}', LogType.INFO)
-                log_text = read_text(path2file)
-                if log_text is not None:
-                    self.log_texts[path2file] = log_text
-                    continue
-                reader = MSeedReader(
-                    path2file,
-                    read_start=self.read_start,
-                    read_end=self.read_end,
-                    is_multiplex=self.is_multiplex,
-                    req_soh_chans=self.req_soh_chans,
-                    req_wf_chans=self.req_wf_chans,
-                    include_mp123zne=self.include_mp123zne,
-                    include_mp456uvw=self.include_mp456uvw,
-                    soh_data=self.soh_data,
-                    mass_pos_data=self.mass_pos_data,
-                    waveform_data=self.waveform_data,
-                    log_data=self.log_data,
-                    gap_minimum=self.gap_minimum)
-                try:
-                    reader.read()
-                    invalid_blockettes = (invalid_blockettes
-                                          or reader.invalid_blockettes)
-                except MSeedReadError:
-                    not_mseed_files.append(file_name)
-                except Exception:
-                    fmt = traceback.format_exc()
-                    self.track_info(f"Skip file {path2file} can't be read "
-                                    f"due to error: {str(fmt)}",
-                                    LogType.WARNING)
-        if not_mseed_files:
+        super().read_folders(self.list_of_dir)
+        if self.not_mseed_files:
             self.track_info(
-                f"Not MSeed files: {not_mseed_files}", LogType.WARNING)
-        if invalid_blockettes:
+                f"Not MSeed files: {self.not_mseed_files}", LogType.WARNING)
+        if self.invalid_blockettes:
             # This check to only print out message once
             print("We currently only handle blockettes 500, 1000,"
                   " and 1001.")
-        self.track_info(
-            f'Skipped {total - count} invalid files.', LogType.INFO)
+
+    def read_file(self, path2file: Path, file_name: str,
+                  count: int, total: int) -> None:
+        """
+        Read data or text from file
+        :param path2file: absolute path to file
+        :param file_name: name of file
+        :param count: total number of file read
+        :param total: total number of all valid files
+        """
+        if count % 10 == 0:
+            self.track_info(
+                f'Read {count}/{total} files', LogType.INFO)
+        log_text = read_text(path2file)
+        if log_text is not None:
+            self.log_texts[path2file] = log_text
+            return
+        reader = MSeedReader(
+            path2file,
+            read_start=self.read_start,
+            read_end=self.read_end,
+            is_multiplex=self.is_multiplex,
+            req_soh_chans=self.req_soh_chans,
+            req_wf_chans=self.req_wf_chans,
+            include_mp123zne=self.include_mp123zne,
+            include_mp456uvw=self.include_mp456uvw,
+            soh_data=self.soh_data,
+            mass_pos_data=self.mass_pos_data,
+            waveform_data=self.waveform_data,
+            log_data=self.log_data,
+            gap_minimum=self.gap_minimum)
+        try:
+            reader.read()
+            self.invalid_blockettes = (self.invalid_blockettes
+                                       or reader.invalid_blockettes)
+        except MSeedReadError:
+            self.not_mseed_files.append(file_name)
 
     def retrieve_nets_from_data_dicts(self):
         """
diff --git a/sohstationviewer/model/reftek_data/log_info.py b/sohstationviewer/model/reftek_data/log_info.py
index 70e5a111fd5a5a8d2ec43c25d69c4b56f0a4a0ff..486efcb069cedebd70ce136d9f5bb2bdcb9d1b98 100644
--- a/sohstationviewer/model/reftek_data/log_info.py
+++ b/sohstationviewer/model/reftek_data/log_info.py
@@ -1,10 +1,12 @@
 from __future__ import annotations
-from typing import Callable, Tuple, List, Union, Set, TYPE_CHECKING
+from typing import Callable, Tuple, List, Union, Set, Dict, TYPE_CHECKING
 
 from sohstationviewer.conf import constants
 from sohstationviewer.controller.util import (
     get_time_6, get_time_4, get_val, rtn_pattern)
 from sohstationviewer.view.util.enums import LogType
+from sohstationviewer.model.reftek_data.log_info_helper import (
+    remove_question_marks)
 
 if TYPE_CHECKING:
     from sohstationviewer.model.reftek_data.reftek import RT130
@@ -33,7 +35,7 @@ class LogInfo():
         self.key = key
         self.unit_id, self.exp_no = key
         self.req_data_streams = req_data_streams
-        self.req_soh_chans = req_soh_chans
+        self.no_question_req_soh_chans = remove_question_marks(req_soh_chans)
         self.is_log_file = is_log_file
         """
         track_year to add year to time since year time not include year after
@@ -49,7 +51,7 @@ class LogInfo():
             self.model = "72A"
         self.max_epoch = 0
         self.min_epoch = constants.HIGHEST_INT
-        self.chans: dict = self.parent.soh_data[self.key]
+        self.chans: Dict = self.parent.soh_data[self.key]
         self.cpu_vers: Set[str] = set()
         self.gps_vers: Set[str] = set()
         self.extract_info()
@@ -314,9 +316,10 @@ class LogInfo():
         :param d: float - value of data
         :param idx: int - index of SOH message line
         """
-
-        if self.req_soh_chans and chan_id not in self.req_soh_chans:
+        if self.no_question_req_soh_chans and not chan_id.startswith(
+                tuple(self.no_question_req_soh_chans)):
             return
+
         if chan_id not in self.chans:
             self.chans[chan_id] = {
                 'reftek': True,
diff --git a/sohstationviewer/model/reftek_data/log_info_helper.py b/sohstationviewer/model/reftek_data/log_info_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..3c3180ed08ab37f48b8d614f909141a5c75c956b
--- /dev/null
+++ b/sohstationviewer/model/reftek_data/log_info_helper.py
@@ -0,0 +1,14 @@
+def remove_question_marks(req_soh_chan):
+    """
+    Remove the question marks in the channel request list, req_soh_chan
+    :param req_soh_chan: soh channel request list
+    :return no_question_req_soh_chan: the channel request list with the
+        question marks removed
+    """
+    no_question_req_soh_chan = []
+    for idx, req in enumerate(req_soh_chan):
+        if req.endswith('?'):
+            no_question_req_soh_chan.append(req_soh_chan[idx][:-1])
+        else:
+            no_question_req_soh_chan.append(req_soh_chan[idx])
+    return no_question_req_soh_chan
diff --git a/sohstationviewer/model/reftek_data/reftek.py b/sohstationviewer/model/reftek_data/reftek.py
index aac4339467c115eeaf2751fe130a9bacef6a2f78..c60514f9dd52c7bee284c17dac7b73ade78e6568 100755
--- a/sohstationviewer/model/reftek_data/reftek.py
+++ b/sohstationviewer/model/reftek_data/reftek.py
@@ -1,7 +1,6 @@
 """
 RT130 object to hold and process RefTek data
 """
-import os
 from pathlib import Path
 from typing import Union, List, Tuple, Dict
 import traceback
@@ -9,7 +8,6 @@ import numpy as np
 from obspy.core import Stream
 
 from sohstationviewer.conf import constants
-from sohstationviewer.controller.util import validate_file
 from sohstationviewer.view.util.enums import LogType
 
 from sohstationviewer.model.general_data.general_data import \
@@ -64,13 +62,8 @@ class RT130(GeneralData):
     def processing_data(self):
         if self.creator_thread.isInterruptionRequested():
             raise ThreadStopped()
-        self.read_folder(self.dir)
-
-        if self.creator_thread.isInterruptionRequested():
-            raise ThreadStopped()
+        self.read_folders()
         self.selected_key = self.select_key()
-        if self.selected_key is None:
-            raise ThreadStopped()
 
         if self.creator_thread.isInterruptionRequested():
             raise ThreadStopped()
@@ -109,51 +102,34 @@ class RT130(GeneralData):
                 # this happens when there is text or ascii only in the data
                 self.data_time[key] = [self.read_start, self.read_end]
 
-    def read_folder(self, folder: str) -> None:
+    def read_folders(self) -> None:
         """
-        Loop all files in dir/list_of_rt130_paths to read for soh data,
-            mass position data and
-            index waveform data with filename and corresponding time range
-
-        :param folder: absolute path to data set folder
+        Read data from list_of_dir or list_of_rt130_paths for soh,
+            mass position and waveform.
         """
-        count = 0
-
-        total = 0
         if self.list_of_rt130_paths != []:
             folders = self.list_of_rt130_paths
-            for folder in folders:
-                total += sum([len(files) for _, _, files in os.walk(folder)])
         else:
-            folders = [self.dir]
-            total = sum([len(files) for _, _, files in os.walk(self.dir)])
-
-        for folder in folders:
-            if not os.path.isdir(folder):
-                raise ProcessingDataError(f"Path '{folder}' not exist")
-            for path, subdirs, files in os.walk(folder):
-                for file_name in files:
-                    if self.creator_thread.isInterruptionRequested():
-                        raise ThreadStopped()
-                    path2file = Path(path).joinpath(file_name)
-                    if not validate_file(path2file, file_name):
-                        continue
-                    try:
-                        if not self.read_reftek_130(path2file):
-                            read_text(path2file, self.log_data['TEXT'])
-                    except Exception:
-                        fmt = traceback.format_exc()
-                        self.track_info(f"Skip file {path2file} can't be read "
-                                        f"due to error: {str(fmt)}",
-                                        LogType.WARNING)
-
-                    count += 1
-                    if count % 50 == 0:
-                        self.track_info(
-                            f"Read {count} files/ {total}", LogType.INFO)
-        self.total_datafile = count
-        self.track_info(
-            f'Skipped {total - count} invalid files.', LogType.INFO)
+            folders = self.list_of_dir
+        super().read_folders(folders)
+
+    def read_file(self, path2file: Path, file_name: str,
+                  count: int, total: int) -> None:
+        """
+        Read data or text from file
+        :param path2file: absolute path to file
+        :param file_name: name of file
+        :param count: total number of file read
+        :param total: total number of all valid files
+        """
+        if count % 50 == 0:
+            self.track_info(
+                f"Read {count}/{total} files", LogType.INFO)
+        log_text = read_text(path2file)
+        if log_text is not None:
+            self.log_texts['TEXT'].append(log_text)
+            return
+        self.read_reftek_130(path2file)
 
     def select_key(self) -> Tuple[str, str]:
         """
@@ -174,7 +150,7 @@ class RT130(GeneralData):
             raise ProcessingDataError(msg)
 
         selected_key = keys[0]
-        if len(keys) > 1:
+        if not self.on_unittest and len(keys) > 1:
             msg = ("There are more than one keys in the given data.\n"
                    "Please select one to display")
             self.pause_signal.emit(msg, keys)
diff --git a/sohstationviewer/view/calendar/calendar_dialog.py b/sohstationviewer/view/calendar/calendar_dialog.py
index ceb2e9ea16242dcc118b2255bb1c9203b442075a..48a491bbf2af868bd9d7425ab3e9ec2b9e3ab718 100644
--- a/sohstationviewer/view/calendar/calendar_dialog.py
+++ b/sohstationviewer/view/calendar/calendar_dialog.py
@@ -1,4 +1,4 @@
-from PySide2 import QtWidgets
+from PySide6 import QtWidgets
 
 from sohstationviewer.view.ui.calendar_ui_qtdesigner import Ui_CalendarDialog
 
diff --git a/sohstationviewer/view/calendar/calendar_widget.py b/sohstationviewer/view/calendar/calendar_widget.py
index 07996636a2233d8ca31fe11f1e9408a3b9a20e2f..87e1343688cc661d82e14ebd40d577748a261a57 100644
--- a/sohstationviewer/view/calendar/calendar_widget.py
+++ b/sohstationviewer/view/calendar/calendar_widget.py
@@ -1,4 +1,4 @@
-from PySide2 import QtCore, QtGui, QtWidgets
+from PySide6 import QtCore, QtGui, QtWidgets
 
 
 class CalendarWidget(QtWidgets.QCalendarWidget):
diff --git a/sohstationviewer/view/channel_prefer_dialog.py b/sohstationviewer/view/channel_prefer_dialog.py
index 88a05c192b2e94f1cfa8daa1fc481b4116e81d93..dab6f8b103a93c80c39d7a8947b4fd52f5e452cb 100755
--- a/sohstationviewer/view/channel_prefer_dialog.py
+++ b/sohstationviewer/view/channel_prefer_dialog.py
@@ -1,8 +1,8 @@
 from typing import Dict, List, Union
 from pathlib import Path
 
-from PySide2 import QtWidgets, QtCore
-from PySide2.QtWidgets import QDialogButtonBox, QDialog, QPlainTextEdit, \
+from PySide6 import QtWidgets, QtCore
+from PySide6.QtWidgets import QDialogButtonBox, QDialog, QPlainTextEdit, \
     QMainWindow
 
 from sohstationviewer.database.process_db import (
@@ -48,7 +48,7 @@ class InputDialog(QDialog):
 
 
 class ChannelPreferDialog(OneWindowAtATimeDialog):
-    def __init__(self, parent: QMainWindow, dir_names: List[Path]):
+    def __init__(self, parent: QMainWindow, list_of_dir: List[Path]):
         """
         Dialog to create lists of preferred SOH channels that users want to
             select for plotting.
@@ -57,11 +57,11 @@ class ChannelPreferDialog(OneWindowAtATimeDialog):
 
         :param parent: widget that calls this plotting
             widget
-        :param dir_names: list of absolute paths of data sets
+        :param list_of_dir: list of absolute paths of data sets
         """
         super(ChannelPreferDialog, self).__init__()
         self.parent = parent
-        self.dir_names = dir_names
+        self.list_of_dir = list_of_dir
         self.setWindowTitle("SOH Channel Preferences")
         self.setGeometry(100, 100, 1100, 800)
         main_layout = QtWidgets.QVBoxLayout()
@@ -91,7 +91,7 @@ class ChannelPreferDialog(OneWindowAtATimeDialog):
         """
         self.add_db_chan_btn: Union[QtWidgets.QPushButton, None] = None
         """
-        scan_chan_btn: Button to scan through all channels from dir_names
+        scan_chan_btn: Button to scan through all channels from list_of_dir
             folder for the list of channels and data type to add
             to the current row
         """
@@ -198,7 +198,7 @@ class ChannelPreferDialog(OneWindowAtATimeDialog):
         self.scan_chan_btn = QtWidgets.QPushButton(
             self, text='Scan Channels from MSeed Data')
         self.scan_chan_btn.clicked.connect(self.scan_channels)
-        if self.dir_names == [] or self.parent.data_type == "RT130":
+        if self.list_of_dir == [] or self.parent.data_type == "RT130":
             self.scan_chan_btn.setEnabled(False)
         h_layout.addWidget(self.scan_chan_btn)
 
@@ -361,7 +361,7 @@ class ChannelPreferDialog(OneWindowAtATimeDialog):
     def edit_soh_list(self, row_idx):
         soh_list_item = self.soh_list_table_widget.item(row_idx, COL['IDs'])
         edit_dialog = InputDialog(text=soh_list_item.text())
-        if edit_dialog.exec_():
+        if edit_dialog.exec():
             soh_list_item.setText(edit_dialog.get_input())
 
     @QtCore.Slot()
@@ -431,7 +431,7 @@ class ChannelPreferDialog(OneWindowAtATimeDialog):
     @QtCore.Slot()
     def scan_channels(self):
         """
-        Scan for all available channels in folder self.dir_names to add to
+        Scan for all available channels in self.list_of_dir to add to
             preferred channel list.
         For RT130, all SOH channels are kept in a log file. It will be more
             reasonable to get channels from DB because the task of getting
@@ -457,15 +457,17 @@ class ChannelPreferDialog(OneWindowAtATimeDialog):
             if result == QtWidgets.QMessageBox.Ok:
                 self.add_db_channels()
         else:
+            self.scan_chan_btn.setEnabled(True)
             # clear all key radio buttons
             for i in reversed(range(self.data_set_key_layout.count())):
                 widget = self.data_set_key_layout.takeAt(i).widget()
                 if widget is not None:
                     widget.setParent(None)
             self.channel_info = read_mseed_channels(
-                self.tracking_info_text_browser, self.dir_names, is_multiplex)
+                self.tracking_info_text_browser,
+                self.list_of_dir, is_multiplex)
             if len(self.channel_info) == 0:
-                msg = "No data can be read from " + ', '.join(self.dir_names)
+                msg = "No data can be read from " + ', '.join(self.list_of_dir)
                 return QtWidgets.QMessageBox.warning(self, "No data", msg)
             self.scan_chan_btn.setEnabled(True)
             self.data_set_key_layout.addWidget(QtWidgets.QLabel("Data Key:"))
diff --git a/sohstationviewer/view/date_edit_with_doy.py b/sohstationviewer/view/date_edit_with_doy.py
index 5fc3ea5bd23128577da8b96d217474e783bb9b4e..a93fa143ade745f2250bc0a71a2f9567695b27e1 100644
--- a/sohstationviewer/view/date_edit_with_doy.py
+++ b/sohstationviewer/view/date_edit_with_doy.py
@@ -1,9 +1,9 @@
-from PySide2.QtCore import Qt, QDate
-from PySide2.QtGui import (
-    QKeyEvent, QWheelEvent, QContextMenuEvent,
+from PySide6.QtCore import Qt, QDate
+from PySide6.QtGui import (
+    QKeyEvent, QWheelEvent, QContextMenuEvent, QAction
 )
-from PySide2.QtWidgets import (
-    QDateEdit, QLineEdit, QMenu, QAction,
+from PySide6.QtWidgets import (
+    QDateEdit, QLineEdit, QMenu,
 )
 
 
@@ -86,7 +86,7 @@ class DayOfYearSupportedDateTextBox(QDateEdit):
 
         menu.addAction(copy_action)
         menu.addAction(select_all_action)
-        menu.exec_(event.globalPos())
+        menu.exec(event.globalPos())
 
     def setDisplayFormat(self, format):
         """
diff --git a/sohstationviewer/view/db_config/db_config_dialog.py b/sohstationviewer/view/db_config/db_config_dialog.py
index 151fe6bb19897967c8e5bfd4382f975261cf6d0f..7c6b1fd3cc8035a9ad64b35da90e3d6f9a460009 100755
--- a/sohstationviewer/view/db_config/db_config_dialog.py
+++ b/sohstationviewer/view/db_config/db_config_dialog.py
@@ -1,7 +1,7 @@
 from __future__ import annotations
 from typing import Set, Dict
 
-from PySide2 import QtWidgets, QtGui, QtCore
+from PySide6 import QtWidgets, QtGui, QtCore
 
 from sohstationviewer.database.process_db import execute_db
 from sohstationviewer.view.util.one_instance_at_a_time import \
@@ -268,7 +268,7 @@ class UiDBInfoDialog(OneWindowAtATimeDialog):
             msgbox.setText(msg)
             msgbox.addButton(QtWidgets.QMessageBox.Cancel)
             msgbox.addButton('Continue', QtWidgets.QMessageBox.YesRole)
-            result = msgbox.exec_()
+            result = msgbox.exec()
             if result == QtWidgets.QMessageBox.Cancel:
                 return
         self.close()
diff --git a/sohstationviewer/view/db_config/param_dialog.py b/sohstationviewer/view/db_config/param_dialog.py
index 21ecf7bcca7316e30a6b5e7253d7f1ce19ef400b..2a5b6f1312c7aec2efa3f04b3d7d5514bccc2638 100755
--- a/sohstationviewer/view/db_config/param_dialog.py
+++ b/sohstationviewer/view/db_config/param_dialog.py
@@ -5,9 +5,9 @@ NOTE: Cannot remove or change params that are already used for channels.
 """
 from typing import List
 
-from PySide2 import QtWidgets, QtCore
-from PySide2.QtCore import Qt
-from PySide2.QtWidgets import QComboBox, QWidget
+from PySide6 import QtWidgets, QtCore
+from PySide6.QtCore import Qt
+from PySide6.QtWidgets import QComboBox, QWidget
 
 from sohstationviewer.conf.constants import ColorMode, ALL_COLOR_MODES
 from sohstationviewer.view.util.plot_func_names import plot_functions
diff --git a/sohstationviewer/view/file_information/file_info_widget.py b/sohstationviewer/view/file_information/file_info_widget.py
index 8c523ef13b937d0d755884652822cfd42228fa20..e6d155e0ec9f046b4e65eae551105edb1b07e33f 100644
--- a/sohstationviewer/view/file_information/file_info_widget.py
+++ b/sohstationviewer/view/file_information/file_info_widget.py
@@ -1,9 +1,9 @@
-from PySide2 import QtCore
-from PySide2.QtGui import (
+from PySide6 import QtCore
+from PySide6.QtGui import (
     QContextMenuEvent, QGuiApplication, QKeySequence,
-    QKeyEvent,
+    QKeyEvent, QAction
 )
-from PySide2.QtWidgets import QListWidget, QMenu, QAction
+from PySide6.QtWidgets import QListWidget, QMenu
 
 
 class FileInfoWidget(QListWidget):
@@ -27,7 +27,7 @@ class FileInfoWidget(QListWidget):
 
         menu.addAction(copy_action)
         menu.addAction(select_all_action)
-        menu.exec_(event.globalPos())
+        menu.exec(event.globalPos())
 
     def keyPressEvent(self, event: QKeyEvent) -> None:
         if event.matches(QKeySequence.Copy):
diff --git a/sohstationviewer/view/file_information/get_file_information.py b/sohstationviewer/view/file_information/get_file_information.py
index aa3b3dd8142ee77dcf7c066a169d80234cbde8e8..a1dab80d1225d0566b0782b993075c271def926d 100644
--- a/sohstationviewer/view/file_information/get_file_information.py
+++ b/sohstationviewer/view/file_information/get_file_information.py
@@ -28,8 +28,11 @@ def extract_data_set_info(data_obj: Union[GeneralData, RT130, MSeed],
     """
 
     data_set_info = {}
-    sources_read = data_obj.dir
-    data_set_info['Sources Read'] = sources_read.name
+    folders = (data_obj.list_of_rt130_paths
+               if data_obj.list_of_dir == [''] else data_obj.list_of_dir)
+
+    sources_read = ', '.join([dir.name for dir in folders])
+    data_set_info['Sources Read'] = sources_read
 
     data_type = data_obj.data_type
     data_set_info['Data Type'] = data_type
diff --git a/sohstationviewer/view/file_list_widget.py b/sohstationviewer/view/file_list_widget.py
index 8af3da9fe8c01d1d385ccd8ab12e26a9a52b60f8..37389846888f619fabc8d5822f705d8134e79a6f 100644
--- a/sohstationviewer/view/file_list_widget.py
+++ b/sohstationviewer/view/file_list_widget.py
@@ -1,4 +1,4 @@
-from PySide2 import QtWidgets
+from PySide6 import QtWidgets
 
 
 class FileListItem(QtWidgets.QListWidgetItem):
diff --git a/sohstationviewer/view/help_view.py b/sohstationviewer/view/help_view.py
index d66da2f13c1b7c5189140afbe6a0e37d5783ff93..a8618b0504b339e68c4151295843376ec4b61bd5 100644
--- a/sohstationviewer/view/help_view.py
+++ b/sohstationviewer/view/help_view.py
@@ -2,8 +2,8 @@ import sys
 from pathlib import Path
 from typing import Tuple, Callable, Union, List, Dict
 
-from PySide2 import QtCore, QtGui, QtWidgets
-from PySide2.QtWidgets import QStyle
+from PySide6 import QtCore, QtGui, QtWidgets
+from PySide6.QtWidgets import QStyle
 
 from sohstationviewer.view.util.functions import (
     create_search_results_file, create_table_of_content_file)
@@ -538,7 +538,7 @@ def main():
 
     wnd = HelpBrowser(home_path='../../')
     wnd.show()
-    sys.exit(app.exec_())
+    sys.exit(app.exec())
 
 
 if __name__ == '__main__':
diff --git a/sohstationviewer/view/main_window.py b/sohstationviewer/view/main_window.py
index 57ac482cb87e2690a07e25e998a5f859b19437c8..e95ed3ff8ad3101df0c1acaaf66f06d425acfa2e 100755
--- a/sohstationviewer/view/main_window.py
+++ b/sohstationviewer/view/main_window.py
@@ -5,10 +5,10 @@ from datetime import datetime
 from typing import List, Tuple, Union, Dict
 from pathlib import Path
 
-from PySide2 import QtCore, QtWidgets, QtGui
-from PySide2.QtCore import QSize
-from PySide2.QtGui import QFont, QPalette, QColor
-from PySide2.QtWidgets import QFrame, QListWidgetItem, QMessageBox
+from PySide6 import QtCore, QtWidgets, QtGui
+from PySide6.QtCore import QSize
+from PySide6.QtGui import QFont, QPalette, QColor
+from PySide6.QtWidgets import QFrame, QListWidgetItem, QMessageBox
 
 from sohstationviewer.model.data_loader import DataLoader
 from sohstationviewer.model.general_data.general_data import \
@@ -60,7 +60,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
         """
         dir_names: list of absolute paths of data sets
         """
-        self.dir_names: List[Path] = []
+        self.list_of_dir: List[Path] = []
         """
         current_dir: the current main data directory
         """
@@ -277,7 +277,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
             front.
         """
         try:
-            self.read_from_file_list()
+            self.get_file_list()
         except Exception as e:
             msg = f"{str(e)}!!!\n\nDo you want to continue?"
             result = QtWidgets.QMessageBox.question(
@@ -286,7 +286,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
             if result == QtWidgets.QMessageBox.No:
                 return
         try:
-            win = ChannelPreferDialog(self, self.dir_names)
+            win = ChannelPreferDialog(self, self.list_of_dir)
             win.show()
         except DialogAlreadyOpenedError:
             ChannelPreferDialog.current_instance.activateWindow()
@@ -393,7 +393,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
         fd = QtWidgets.QFileDialog(self)
         fd.setFileMode(QtWidgets.QFileDialog.Directory)
         fd.setDirectory(self.curr_dir_line_edit.text())
-        fd.exec_()
+        fd.exec()
         try:
             new_path = fd.selectedFiles()[0]
             self.set_current_directory(new_path)
@@ -470,13 +470,13 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
         return (self.pref_soh_list
                 if not self.all_soh_chans_check_box.isChecked() else [])
 
-    def read_from_file_list(self):
+    def get_file_list(self):
         """
         Read from self.open_files_list to identify
             self.dir_names/self.selected_rt130_paths.
         self.data_type is identified here too.
         """
-        self.dir_names = ['']
+        self.list_of_dir = ['']
         self.selected_rt130_paths = []
         root_dir = Path(self.curr_dir_line_edit.text())
         if self.rt130_das_dict != {}:
@@ -494,28 +494,29 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
             # displayed in File List box. The current dir (root_dir) will be
             # the only one of the selected dir for user to start processing
             # from.
-            self.dir_names = [root_dir]
+            self.list_of_dir = [root_dir]
             if self.data_radio_button.isEnabled():
                 # In case of Baler's data, there will be 2 data folders for
                 # user to select from, data/ and sdata/. The radio buttons
                 # data and sdata allow user to select from Main Window.
                 if self.data_radio_button.isChecked():
-                    self.dir_names = [root_dir.joinpath('data')]
+                    self.list_of_dir = [root_dir.joinpath('data')]
                 else:
-                    self.dir_names = [root_dir.joinpath('sdata')]
+                    self.list_of_dir = [root_dir.joinpath('sdata')]
         else:
             # When "From Data Card" checkbox is checked, sub directories of the
             # current dir (root_dir) will be displayed in File List box.
             # User can select one or more sub-directories to process from.
-            self.dir_names = [root_dir.joinpath(item.text())
-                              for item in self.open_files_list.selectedItems()]
-            if self.dir_names == []:
+            self.list_of_dir = [
+                root_dir.joinpath(item.text())
+                for item in self.open_files_list.selectedItems()]
+            if self.list_of_dir == []:
                 msg = "No directories have been selected."
                 raise Exception(msg)
 
         if self.rt130_das_dict == {}:
             self.data_type, self.is_multiplex = detect_data_type(
-                self.dir_names)
+                self.list_of_dir)
 
     def clear_plots(self):
         self.plotting_widget.clear()
@@ -601,7 +602,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
             pass
 
         try:
-            self.read_from_file_list()
+            self.get_file_list()
         except Exception as e:
             if 'no known data detected' in str(e):
                 msgbox = QtWidgets.QMessageBox()
@@ -609,7 +610,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
                 msgbox.setText(str(e))
                 msgbox.addButton(QtWidgets.QMessageBox.Cancel)
                 msgbox.addButton('Continue', QtWidgets.QMessageBox.YesRole)
-                result = msgbox.exec_()
+                result = msgbox.exec()
                 if result == QtWidgets.QMessageBox.Cancel:
                     self.cancel_loading()
                     return
@@ -634,7 +635,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
                                                    QMessageBox.Abort)
             data_too_big_dialog.setDefaultButton(QMessageBox.Abort)
             data_too_big_dialog.setIcon(QMessageBox.Question)
-            ret = data_too_big_dialog.exec_()
+            ret = data_too_big_dialog.exec()
             if ret == QMessageBox.Abort:
                 self.cancel_loading()
                 return
@@ -654,15 +655,15 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
         self.end_tm = datetime.strptime(end_tm_str, TM_FORMAT).timestamp()
 
         self.gps_dialog.clear_plot()
-        self.gps_dialog.data_path = self.dir_names[0]
-        self.gps_dialog.set_export_directory(str(self.dir_names[0]))
+        self.gps_dialog.data_path = self.curr_dir_line_edit.text()
+        self.gps_dialog.set_export_directory(self.curr_dir_line_edit.text())
         self.gps_dialog.gps_points = []
 
         self.data_loader.init_loader(
             self.data_type,
             self.tracking_info_text_browser,
             self.is_multiplex,
-            self.dir_names,
+            self.list_of_dir,
             self.selected_rt130_paths,
             req_wf_chans=self.req_wf_chans,
             req_soh_chans=self.req_soh_chans,
@@ -828,8 +829,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
             self.is_plotting_tps = True
             peer_plotting_widgets.append(self.tps_dlg.plotting_widget)
             self.tps_dlg.set_data(
-                self.data_type,
-                ','.join([str(d) for d in self.dir_names]))
+                self.data_type, ','.join([str(d) for d in self.list_of_dir]))
             self.tps_dlg.show()
             # The waveform and TPS plots is being stopped at the same time, so
             # we can't simply reset all flags. Instead, we use an intermediate
@@ -850,8 +850,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
             # waveformPlot
             peer_plotting_widgets.append(self.waveform_dlg.plotting_widget)
             self.waveform_dlg.set_data(
-                self.data_type,
-                ','.join([str(d) for d in self.dir_names]))
+                self.data_type, ','.join([str(d) for d in self.list_of_dir]))
             self.waveform_dlg.show()
             waveform_widget = self.waveform_dlg.plotting_widget
             waveform_widget.stopped.connect(self.reset_is_plotting_waveform)
@@ -1099,7 +1098,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow):
             print(f"DEVELOPING ERROR: Type of form must be 'QWidget' instead "
                   f"of '{form.__class__.__name__}'")
         if form not in self.forms_in_forms_menu:
-            action = QtWidgets.QAction(form_name, self)
+            action = QtGui.QAction(form_name, self)
             self.forms_menu.addAction(action)
             action.triggered.connect(lambda: self.raise_form(form))
             self.forms_in_forms_menu.append(form)
diff --git a/sohstationviewer/view/plotting/gps_plot/gps_dialog.py b/sohstationviewer/view/plotting/gps_plot/gps_dialog.py
index e2221bcf9f8892ec766d28eca8a04244c25a44e7..96e5d1fd50172af028c73e2000d3801c9ae234c0 100644
--- a/sohstationviewer/view/plotting/gps_plot/gps_dialog.py
+++ b/sohstationviewer/view/plotting/gps_plot/gps_dialog.py
@@ -5,7 +5,7 @@ import traceback
 from pathlib import Path
 from typing import List, Optional, Literal, Iterable
 
-from PySide2 import QtWidgets, QtCore
+from PySide6 import QtWidgets, QtCore
 from matplotlib.axes import Axes
 from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas
 from matplotlib.figure import Figure
@@ -326,7 +326,7 @@ class GPSDialog(QtWidgets.QWidget):
         fd = QtWidgets.QFileDialog(self)
         fd.setFileMode(QtWidgets.QFileDialog.Directory)
         fd.setDirectory(self.export_dir_textbox.text())
-        fd.exec_()
+        fd.exec()
         new_path = fd.selectedFiles()[0]
         self.set_export_directory(new_path)
 
@@ -432,4 +432,4 @@ if __name__ == '__main__':
     wnd.data_path = Path(data_path)
     wnd.show()
 
-    sys.exit(app.exec_())
+    sys.exit(app.exec())
diff --git a/sohstationviewer/view/plotting/plotting_widget/multi_threaded_plotting_widget.py b/sohstationviewer/view/plotting/plotting_widget/multi_threaded_plotting_widget.py
index 511aba4e21b09e40c966436155a7c59cb0691e7f..58ed3507dded12719e6565ecb6a35565afbf43f7 100644
--- a/sohstationviewer/view/plotting/plotting_widget/multi_threaded_plotting_widget.py
+++ b/sohstationviewer/view/plotting/plotting_widget/multi_threaded_plotting_widget.py
@@ -2,7 +2,7 @@
 
 from typing import Tuple, Union, Dict, List
 
-from PySide2 import QtCore
+from PySide6 import QtCore
 
 from sohstationviewer.model.data_type_model import DataTypeModel
 
@@ -74,7 +74,7 @@ class MultiThreadedPlottingWidget(PlottingWidget):
         :param time_ticks_total: max number of tick to show on time bar
         :param is_waveform: True if this is a WaveformWidget, otherwise False
         """
-
+        self.zoom_marker1_shown = False
         self.key = key
         self.processing_log = []  # [(message, type)]
         self.gap_bar = None
diff --git a/sohstationviewer/view/plotting/plotting_widget/plotting_processor.py b/sohstationviewer/view/plotting/plotting_widget/plotting_processor.py
index 764369320011cf6b6df691b599b165a937a54d4f..5ca9a6f4be004b137640d0f78f6e574abbab37e2 100644
--- a/sohstationviewer/view/plotting/plotting_widget/plotting_processor.py
+++ b/sohstationviewer/view/plotting/plotting_widget/plotting_processor.py
@@ -1,4 +1,4 @@
-from PySide2 import QtCore
+from PySide6 import QtCore
 
 from sohstationviewer.conf import constants as const
 from sohstationviewer.view.plotting.plotting_widget.plotting_processor_helper\
diff --git a/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py b/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py
index 970ba1903f2ba734848ea36cd29d45c6b523006c..1dbe7740382add4e52a96fa3e3d0a7a2a68f6871 100755
--- a/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py
+++ b/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py
@@ -6,9 +6,9 @@ import numpy as np
 import matplotlib.text
 from matplotlib import pyplot as pl
 from matplotlib.transforms import Bbox
-from PySide2.QtCore import QTimer, Qt
-from PySide2 import QtCore, QtWidgets
-from PySide2.QtWidgets import QWidget, QApplication, QTextBrowser
+from PySide6.QtCore import QTimer, Qt
+from PySide6 import QtCore, QtWidgets
+from PySide6.QtWidgets import QWidget, QApplication, QTextBrowser
 
 from sohstationviewer.conf import constants
 from sohstationviewer.view.util.color import set_color_mode
@@ -296,9 +296,9 @@ class PlottingWidget(QtWidgets.QScrollArea):
             focus SOH tab, roll to the corresponding line.
         """
         artist = event.artist
-        ax = artist.axes
-        chan_id = ax.chan
         if isinstance(artist, pl.Line2D):
+            ax = artist.axes
+            chan_id = ax.chan
             chan_data = self.plotting_data1[chan_id]
             # list of x values of the plot
             x_list = artist.get_xdata()
@@ -650,7 +650,7 @@ class PlottingWidget(QtWidgets.QScrollArea):
             msgbox.setText(msg)
             msgbox.addButton(QtWidgets.QMessageBox.Cancel)
             msgbox.addButton('Continue', QtWidgets.QMessageBox.YesRole)
-            result = msgbox.exec_()
+            result = msgbox.exec()
             if result == QtWidgets.QMessageBox.Cancel:
                 return
             self.main_window.color_mode = self.c_mode
@@ -667,12 +667,12 @@ class PlottingWidget(QtWidgets.QScrollArea):
             msgbox.setText(msg)
             msgbox.addButton(QtWidgets.QMessageBox.Cancel)
             msgbox.addButton('Continue', QtWidgets.QMessageBox.YesRole)
-            result = msgbox.exec_()
+            result = msgbox.exec()
             if result == QtWidgets.QMessageBox.Cancel:
                 return
         save_plot_dlg = SavePlotDialog(
             self.parent, self.main_window, default_name)
-        save_plot_dlg.exec_()
+        save_plot_dlg.exec()
         save_file_path = save_plot_dlg.save_file_path
         if save_file_path is None:
             return
diff --git a/sohstationviewer/view/plotting/time_power_squared_dialog.py b/sohstationviewer/view/plotting/time_power_squared_dialog.py
index 5e533b53b591894908a59bca12eb8899c5dde0d3..6778c093c2c8447ad974703da1784239a6c2e75d 100755
--- a/sohstationviewer/view/plotting/time_power_squared_dialog.py
+++ b/sohstationviewer/view/plotting/time_power_squared_dialog.py
@@ -3,7 +3,7 @@ from math import sqrt
 from typing import List, Tuple, Union
 
 import numpy as np
-from PySide2 import QtWidgets, QtCore
+from PySide6 import QtWidgets, QtCore
 
 from sohstationviewer.conf import constants as const
 from sohstationviewer.controller.plotting_data import (
@@ -86,6 +86,7 @@ class TimePowerSquaredWidget(plotting_widget.PlottingWidget):
         :param start_tm: requested start time to read
         :param end_tm: requested end time to read
         """
+        self.zoom_marker1_shown = False
         self.is_working = True
         self.set_key = key
         self.plotting_data1 = d_obj.waveform_data[key]
diff --git a/sohstationviewer/view/plotting/time_power_squared_processor.py b/sohstationviewer/view/plotting/time_power_squared_processor.py
index c554c6867417f25344fcbb5387a1f9c74faccdb9..200ea544cef82ab3c8a608654e6431f38894201a 100644
--- a/sohstationviewer/view/plotting/time_power_squared_processor.py
+++ b/sohstationviewer/view/plotting/time_power_squared_processor.py
@@ -1,7 +1,7 @@
 from typing import Dict, Optional, List
 
 import numpy as np
-from PySide2 import QtCore
+from PySide6 import QtCore
 
 from sohstationviewer.view.plotting.time_power_squared_helper import \
     get_tps_for_discontinuous_data
diff --git a/sohstationviewer/view/plotting/waveform_dialog.py b/sohstationviewer/view/plotting/waveform_dialog.py
index 24c9a9a8cfb2256c3f40f1a7ef7bbe7776f4305d..2e9cf40b8325fce4da409f71289663cb07eb378a 100755
--- a/sohstationviewer/view/plotting/waveform_dialog.py
+++ b/sohstationviewer/view/plotting/waveform_dialog.py
@@ -1,7 +1,7 @@
 # Drawing waveform and mass position
 
 from typing import Tuple, Union, Dict
-from PySide2 import QtCore, QtWidgets
+from PySide6 import QtCore, QtWidgets
 
 from sohstationviewer.model.data_type_model import DataTypeModel
 
diff --git a/sohstationviewer/view/plotting/waveform_processor.py b/sohstationviewer/view/plotting/waveform_processor.py
index 8d6ef39b2ee84c0d9c681be97b936818785b604e..f98727f0eeff08d0a366a7c2532f730713cff4db 100644
--- a/sohstationviewer/view/plotting/waveform_processor.py
+++ b/sohstationviewer/view/plotting/waveform_processor.py
@@ -1,6 +1,6 @@
 from typing import List, Dict
 
-from PySide2 import QtCore
+from PySide6 import QtCore
 from obspy import UTCDateTime
 from obspy.core import Trace
 
diff --git a/sohstationviewer/view/save_plot_dialog.py b/sohstationviewer/view/save_plot_dialog.py
index 77a988f25a6679ac7ecd3bd4f916ca625d6a97d1..d5e7a5fc1732d2d00de0bdf445fe41ef2bffaeca 100644
--- a/sohstationviewer/view/save_plot_dialog.py
+++ b/sohstationviewer/view/save_plot_dialog.py
@@ -4,8 +4,8 @@ import os
 from pathlib import Path
 from typing import Union, Optional
 
-from PySide2 import QtWidgets, QtCore, QtGui
-from PySide2.QtWidgets import QApplication, QWidget, QDialog
+from PySide6 import QtWidgets, QtCore, QtGui
+from PySide6.QtWidgets import QApplication, QWidget, QDialog
 
 from sohstationviewer.conf import constants
 
@@ -93,7 +93,7 @@ class SavePlotDialog(QDialog):
         fd = QtWidgets.QFileDialog(self)
         fd.setFileMode(QtWidgets.QFileDialog.Directory)
         fd.setDirectory(self.save_dir_textbox.text())
-        fd.exec_()
+        fd.exec()
         new_path = fd.selectedFiles()[0]
         self.save_dir_textbox.setText(new_path)
         self.save_dir_path = new_path
@@ -133,7 +133,7 @@ if __name__ == '__main__':
     save_path = '/Users/ldam/Documents/GIT/sohstationviewer/tests/test_data/Q330-sample'  # noqa: E501
     test = SavePlotDialog(None, 'test_plot')
     test.set_save_directory(save_path)
-    test.exec_()
+    test.exec()
     print("dpi:", test.dpi)
     print("save file path:", test.save_file_path)
-    sys.exit(app.exec_())
+    sys.exit(app.exec())
diff --git a/sohstationviewer/view/search_message/highlight_delegate.py b/sohstationviewer/view/search_message/highlight_delegate.py
index cda425ca1c27191f8c0376f048fc36c06ce8d2ef..50f3f86e94cdbe5b762807414ceef50567f9fd32 100644
--- a/sohstationviewer/view/search_message/highlight_delegate.py
+++ b/sohstationviewer/view/search_message/highlight_delegate.py
@@ -2,8 +2,8 @@
 Credit: https://stackoverflow.com/questions/53353450/how-to-highlight-a-words-in-qtablewidget-from-a-searchlist  # noqa
 """
 from typing import List, Dict
-from PySide2 import QtCore, QtGui, QtWidgets
-from PySide2.QtGui import QPen, QTextCursor, QTextCharFormat, QColor
+from PySide6 import QtCore, QtGui, QtWidgets
+from PySide6.QtGui import QPen, QTextCursor, QTextCharFormat, QColor
 
 
 class HighlightDelegate(QtWidgets.QStyledItemDelegate):
diff --git a/sohstationviewer/view/search_message/search_message_dialog.py b/sohstationviewer/view/search_message/search_message_dialog.py
index 56b4b2355c120f28e5b2ea81f53b80ba4f10429c..8aeb3f2b75607af0cdeb3d84d3d6064e8daead31 100644
--- a/sohstationviewer/view/search_message/search_message_dialog.py
+++ b/sohstationviewer/view/search_message/search_message_dialog.py
@@ -3,8 +3,8 @@ import os
 from pathlib import PosixPath, Path
 from typing import Dict, List, Tuple, Callable, Union, Optional
 
-from PySide2 import QtGui, QtCore, QtWidgets
-from PySide2.QtWidgets import QStyle
+from PySide6 import QtGui, QtCore, QtWidgets
+from PySide6.QtWidgets import QStyle
 
 from sohstationviewer.view.search_message.highlight_delegate import (
     HighlightDelegate)
@@ -705,7 +705,7 @@ def main():
     wnd.show()
     # wnd.show_log_entry_from_data_index(10)
 
-    sys.exit(app.exec_())
+    sys.exit(app.exec())
 
 
 if __name__ == '__main__':
diff --git a/sohstationviewer/view/select_buttons_dialog.py b/sohstationviewer/view/select_buttons_dialog.py
index e8841fe6d5f98a8168a145604927b8f929de9c92..f4efebe38b0c8d9dd8916f313c2fa02503f1bc1c 100644
--- a/sohstationviewer/view/select_buttons_dialog.py
+++ b/sohstationviewer/view/select_buttons_dialog.py
@@ -2,7 +2,7 @@ import sys
 import platform
 import os
 
-from PySide2 import QtWidgets, QtCore
+from PySide6 import QtWidgets, QtCore
 from functools import partial
 
 
@@ -62,7 +62,7 @@ if __name__ == '__main__':
     test = SelectButtonDialog(None, "Testing result from buttons",
                               ['test01', 'test02', 'test03',
                                'test11', 'test12', 'test13'])
-    test.exec_()
+    test.exec()
 
     print("return Code:", test.ret)
-    sys.exit(app.exec_())
+    sys.exit(app.exec())
diff --git a/sohstationviewer/view/ui/about_ui_qtdesigner.py b/sohstationviewer/view/ui/about_ui_qtdesigner.py
index e1ecbbe2258d2ee9909d583d3ec53d7d548f4af6..8c402dd5ad050f0084e538e6ce1b1d36d2782d72 100644
--- a/sohstationviewer/view/ui/about_ui_qtdesigner.py
+++ b/sohstationviewer/view/ui/about_ui_qtdesigner.py
@@ -8,7 +8,7 @@
 #
 # WARNING! All changes made in this file will be lost!
 
-from PySide2 import QtCore, QtGui, QtWidgets
+from PySide6 import QtCore, QtGui, QtWidgets
 
 class Ui_About(object):
     def setupUi(self, About):
diff --git a/sohstationviewer/view/ui/calendar_ui_qtdesigner.py b/sohstationviewer/view/ui/calendar_ui_qtdesigner.py
index 81edc2dd9a6fa013340ce159ef58cd58e61b5b52..4e225c0eafb962bb5748971aa948936558c68d5e 100644
--- a/sohstationviewer/view/ui/calendar_ui_qtdesigner.py
+++ b/sohstationviewer/view/ui/calendar_ui_qtdesigner.py
@@ -8,7 +8,7 @@
 #
 # WARNING! All changes made in this file will be lost!
 
-from PySide2 import QtCore, QtWidgets
+from PySide6 import QtCore, QtWidgets
 
 from sohstationviewer.view.calendar.calendar_widget import CalendarWidget
 
diff --git a/sohstationviewer/view/ui/main_ui.py b/sohstationviewer/view/ui/main_ui.py
index 4c98291a6cc6a45533b847dc17f65cb2f97544ac..d83a14909625275940a25b03145cdb10e7c52cba 100755
--- a/sohstationviewer/view/ui/main_ui.py
+++ b/sohstationviewer/view/ui/main_ui.py
@@ -3,12 +3,14 @@ import configparser
 from pathlib import Path
 from typing import Union, List, Optional
 
-from PySide2 import QtCore, QtGui, QtWidgets
-from PySide2.QtWidgets import (
+from PySide6 import QtCore, QtGui, QtWidgets
+from PySide6.QtWidgets import (
     QMainWindow, QWidget, QTextBrowser, QPushButton, QLineEdit, QDateEdit,
-    QListWidget, QCheckBox, QRadioButton, QMenu, QAction, QLabel, QFrame,
-    QVBoxLayout, QHBoxLayout, QGridLayout, QAbstractItemView, QShortcut,
-    QActionGroup, QButtonGroup,
+    QListWidget, QCheckBox, QRadioButton, QMenu, QLabel, QFrame,
+    QVBoxLayout, QHBoxLayout, QGridLayout, QAbstractItemView, QButtonGroup,
+)
+from PySide6.QtGui import (
+    QAction, QActionGroup, QShortcut
 )
 
 from sohstationviewer.view.calendar.calendar_widget import CalendarWidget
diff --git a/sohstationviewer/view/util/one_instance_at_a_time.py b/sohstationviewer/view/util/one_instance_at_a_time.py
index f0bbf7a34e8103287bd7f4bbe3dd0fa988491304..dd6cd416df8a2d4136b166a6c55e301e128c9000 100644
--- a/sohstationviewer/view/util/one_instance_at_a_time.py
+++ b/sohstationviewer/view/util/one_instance_at_a_time.py
@@ -1,7 +1,7 @@
 from __future__ import annotations
 
-from PySide2.QtGui import QCloseEvent
-from PySide2.QtWidgets import QWidget
+from PySide6.QtGui import QCloseEvent
+from PySide6.QtWidgets import QWidget
 
 
 class DialogAlreadyOpenedError(Exception):
diff --git a/tests/controller/test_processing.py b/tests/controller/test_processing.py
index 899e58e95ba3d3e33ce899685b55fdfff1fd08fa..a607aab9e702df84d73c27df6273eba4dec6129f 100644
--- a/tests/controller/test_processing.py
+++ b/tests/controller/test_processing.py
@@ -12,7 +12,7 @@ from sohstationviewer.controller.processing import (
     get_data_type_from_file
 )
 from sohstationviewer.database.extract_data import get_signature_channels
-from PySide2 import QtWidgets
+from PySide6 import QtWidgets
 
 
 TEST_DATA_DIR = Path(__file__).resolve().parent.parent.joinpath('test_data')
@@ -288,6 +288,22 @@ class TestDetectDataType(TestCase):
             f"{self.dir2.name}: Q330\n\n"
             f"Please have only data that related to each other.")
 
+    def test_same_data_types_different_multiplex(self):
+        """
+        Test basic functionality of detect_data_type - the given directories
+        contain same data types but different multiplex.
+        """
+        returned_data_types = [('Q330', True), ('Q330', False)]
+        self.mock_get_data_type_from_file.side_effect = returned_data_types
+
+        with self.assertRaises(Exception) as context:
+            detect_data_type([self.dir1.name, self.dir2.name])
+        self.assertEqual(
+            str(context.exception),
+            "There are both multiplexed and non-multiplexed data "
+            "detected.\n\nPlease have only data that related to"
+            " each other.")
+
     def test_unknown_data_type(self):
         """
         Test basic functionality of detect_data_type - can't detect any data
diff --git a/tests/controller/test_util.py b/tests/controller/test_util.py
index e58e8c89b84a1a580991722f73490b2787c75ad8..a4f46f8a8f56f865db3c3d3efc08c499b7068259 100644
--- a/tests/controller/test_util.py
+++ b/tests/controller/test_util.py
@@ -18,7 +18,8 @@ from sohstationviewer.controller.util import (
     get_time_4,
     get_val,
     rtn_pattern,
-    add_thousand_separator
+    add_thousand_separator,
+    get_valid_file_count
 )
 
 TEST_DATA_DIR = os.path.realpath(os.path.join(
@@ -367,3 +368,11 @@ class TestFmti(TestCase):
             val = -62362.32523
             expected = '-62,362'
             self.assertEqual(add_thousand_separator(val), expected)
+
+
+class TestGetTotalFiles(TestCase):
+    def test_get_valid_file_count(self):
+        list_of_dir = [os.path.join(TEST_DATA_DIR, 'Centaur-sample'),
+                       os.path.join(TEST_DATA_DIR, 'Q330-sample')]
+        total_files = get_valid_file_count(list_of_dir)
+        self.assertEqual(total_files, 6)
diff --git a/tests/model/mseed_data/test_mseed.py b/tests/model/mseed_data/test_mseed.py
index 8d6835e786e6fa2fcf93a94a5585c1e8dae18216..e12494dccd68a99c6d69e8a6705c9d561faa3739 100644
--- a/tests/model/mseed_data/test_mseed.py
+++ b/tests/model/mseed_data/test_mseed.py
@@ -21,7 +21,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Q330',
             'is_multiplex': False,
-            'folder': '_',
+            'list_of_dir': ['_'],
             'on_unittest': True
         }
         with self.assertRaises(ProcessingDataError) as context:
@@ -36,7 +36,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Pegasus',
             'is_multiplex': False,
-            'folder': pegasus_data,
+            'list_of_dir': [pegasus_data],
             'req_soh_chans': ['_'],
             'on_unittest': True
         }
@@ -59,7 +59,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Pegasus',
             'is_multiplex': False,
-            'folder': pegasus_data,
+            'list_of_dir': [pegasus_data],
             'req_soh_chans': ['VE1'],
             'on_unittest': True
         }
@@ -85,7 +85,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Pegasus',
             'is_multiplex': False,
-            'folder': pegasus_data,
+            'list_of_dir': [pegasus_data],
             'req_wf_chans': ['HH1'],
             'req_soh_chans': ['_'],
             'on_unittest': True
@@ -111,7 +111,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Q330',
             'is_multiplex': False,
-            'folder': q330_data,
+            'list_of_dir': [q330_data],
             'req_soh_chans': ['LOG'],
         }
         obj = MSeed(**args)
@@ -135,7 +135,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Q330',
             'is_multiplex': True,
-            'folder': blockettes_data,
+            'list_of_dir': [blockettes_data],
             'req_soh_chans': ['ACE'],
         }
         obj = MSeed(**args)
@@ -155,7 +155,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Q330',
             'is_multiplex': False,
-            'folder': multiplex_data,
+            'list_of_dir': [multiplex_data],
             'req_soh_chans': [],
             'req_wf_chans': ['EL1']
         }
@@ -177,7 +177,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Q330',
             'is_multiplex': True,
-            'folder': multiplex_data,
+            'list_of_dir': [multiplex_data],
             'req_soh_chans': [],
             'req_wf_chans': ['EL1']
         }
@@ -200,7 +200,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Q330',
             'is_multiplex': False,
-            'folder': multiplex_data,
+            'list_of_dir': [multiplex_data],
             'req_soh_chans': [],
             'req_wf_chans': ['EL2']
         }
@@ -212,7 +212,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Q330',
             'is_multiplex': True,
-            'folder': multiplex_data,
+            'list_of_dir': [multiplex_data],
             'req_soh_chans': [],
             'req_wf_chans': ['EL2']
         }
@@ -229,13 +229,39 @@ class TestMSeed(TestCase):
         self.assertEqual(len(obj.waveform_data['3203']['EL2']['tracesInfo']),
                          1)
 
+    def test_select_2_folders(self):
+        # is_multiplex = True => the selected channel will be read
+        args = {
+            'data_type': 'Q330',
+            'is_multiplex': True,
+            'list_of_dir': [multiplex_data, blockettes_data],
+            'req_soh_chans': [],
+            'req_wf_chans': ['EL2'],
+            'gap_minimum': 60
+        }
+        obj = MSeed(**args)
+        self.assertEqual(list(obj.waveform_data.keys()), ['3203'])
+        self.assertEqual(list(obj.waveform_data['3203'].keys()), ['EL2'])
+        self.assertEqual(obj.waveform_data['3203']['EL2']['samplerate'], 200)
+        self.assertEqual(obj.waveform_data['3203']['EL2']['startTmEpoch'],
+                         1671730004.3100293)
+        self.assertEqual(obj.waveform_data['3203']['EL2']['endTmEpoch'],
+                         1671735657.9148998)
+        self.assertEqual(obj.waveform_data['3203']['EL2']['size'], 268576)
+        self.assertEqual(obj.waveform_data['3203']['EL2']['gaps'],
+                         [[1671730720.5549, 1671735031.2799978]])
+        self.assertEqual(len(obj.waveform_data['3203']['EL2']['tracesInfo']),
+                         1)
+        self.assertEqual(obj.gaps['3203'],
+                         [[1671730720.5549, 1671735031.2799978]])
+
     def test_existing_time_range(self):
         # check if data_time is from the given range, end time may get
         # a little greater than read_end according to record's end time
         args = {
             'data_type': 'Q330',
             'is_multiplex': False,
-            'folder': q330_data,
+            'list_of_dir': [q330_data],
             'req_soh_chans': [],
             'read_start': 1625456018.0,
             'read_end': 1625505627.9998999
@@ -252,7 +278,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Q330',
             'is_multiplex': False,
-            'folder': q330_data,
+            'list_of_dir': [q330_data],
             'req_soh_chans': [],
             'read_start': 1625356018.0,
             'read_end': 1625405627.9998999
@@ -269,7 +295,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Q330',
             'is_multiplex': False,
-            'folder': q330_data,
+            'list_of_dir': [q330_data],
             'req_soh_chans': [],
             'req_wf_chans': ['LHE']
         }
@@ -292,7 +318,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Q330',
             'is_multiplex': True,
-            'folder': q330_data,
+            'list_of_dir': [q330_data],
             'req_soh_chans': [],
             'req_wf_chans': [],
             'include_mp123zne': True
@@ -315,7 +341,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Centaur',
             'is_multiplex': True,
-            'folder': centaur_data,
+            'list_of_dir': [centaur_data],
             'req_soh_chans': [],
             'gap_minimum': 60
         }
@@ -340,7 +366,7 @@ class TestMSeed(TestCase):
         args = {
             'data_type': 'Centaur',
             'is_multiplex': True,
-            'folder': centaur_data,
+            'list_of_dir': [centaur_data],
             'req_soh_chans': [],
             'gap_minimum': None
         }
diff --git a/tests/model/reftek_data/test_reftek.py b/tests/model/reftek_data/test_reftek.py
index 8bb2a71749d59d30833d4c98014308fff58060df..af03b2aa03606d807d0e888b71a0091a0dcc9901 100644
--- a/tests/model/reftek_data/test_reftek.py
+++ b/tests/model/reftek_data/test_reftek.py
@@ -17,7 +17,7 @@ class TestReftek(TestCase):
         # raise exception when path not exist
         args = {
             'data_type': 'RT130',
-            'folder': '_',
+            'list_of_dir': ['_'],
             'rt130_waveform_data_req': False,
             'on_unittest': True
         }
@@ -31,7 +31,7 @@ class TestReftek(TestCase):
     def test_read_soh(self):
         args = {
             'data_type': 'RT130',
-            'folder': reftek_data,
+            'list_of_dir': [reftek_data],
             'req_soh_chans': [],
             'rt130_waveform_data_req': False,
             'on_unittest': True
@@ -56,13 +56,13 @@ class TestReftek(TestCase):
             '\n150:00:00:00 REF TEK 130'
             '\r\n150:00:00:00 CPU SOFTWARE')
         self.assertEqual(list(obj.soh_data.keys()), [('92EB', '25')])
-        self.assertEqual(list(obj.soh_data[('92EB', '25')].keys()),
-                         expected_soh)
+        self.assertEqual(sorted(list(obj.soh_data[('92EB', '25')].keys())),
+                         sorted(expected_soh))
 
     def test_read_waveform(self):
         args = {
             'data_type': 'RT130',
-            'folder': reftek_data,
+            'list_of_dir': [reftek_data],
             'req_soh_chans': [],
             'req_wf_chans': [1],
             'rt130_waveform_data_req': True,
@@ -85,7 +85,7 @@ class TestReftek(TestCase):
     def test_read_mass_pos(self):
         args = {
             'data_type': 'RT130',
-            'folder': reftek_data,
+            'list_of_dir': [reftek_data],
             'req_soh_chans': ['_'],
             'include_mp123zne': True,
             'rt130_waveform_data_req': False,
@@ -107,7 +107,7 @@ class TestReftek(TestCase):
         with self.subTest("no gap_minimum set"):
             args = {
                 'data_type': 'RT130',
-                'folder': reftek_gap_data,
+                'list_of_dir': [reftek_gap_data],
                 'req_soh_chans': [],
                 'req_wf_chans': ['*'],
                 'rt130_waveform_data_req': True,
@@ -129,7 +129,7 @@ class TestReftek(TestCase):
         with self.subTest("has gap_minimum set"):
             args = {
                 'data_type': 'RT130',
-                'folder': reftek_gap_data,
+                'list_of_dir': [reftek_gap_data],
                 'req_soh_chans': [],
                 'req_wf_chans': ['*'],
                 'rt130_waveform_data_req': True,
@@ -148,3 +148,45 @@ class TestReftek(TestCase):
                              ['TEXT', ('98AD', '0')])
             self.assertEqual(obj.gaps[('98AD', '0')],
                              [[1648493999.64, 1648508400.64]])
+
+    def test_select_2_folders(self):
+        args = {
+            'data_type': 'RT130',
+            'list_of_dir': [reftek_data, reftek_gap_data],
+            'req_soh_chans': [],
+            'req_wf_chans': ['*'],
+            'rt130_waveform_data_req': True,
+            'gap_minimum': 60,
+            'on_unittest': True
+        }
+        expected_soh = [
+            'SOH/Data Def', 'Battery Volt', 'DAS Temp', 'Backup Volt',
+            'Disk Usage1', 'Disk Usage2', 'Dump Called/Comp', 'GPS On/Off/Err',
+            'GPS Lk/Unlk', 'Clk Phase Err',  'Event DS1', 'Event DS9']
+        expected_waveform = ['DS1-1', 'DS1-2', 'DS1-3']
+        obj = RT130(**args)
+        self.assertEqual(obj.found_data_streams, [9, 1, 1, 2, 2])
+        self.assertEqual(obj.keys, [('92EB', '25'), ('98AD', '0')])
+        self.assertEqual(obj.selected_key, ('92EB', '25'))
+        self.assertEqual(
+            list(obj.stream_header_by_key_chan[('92EB', '25')].keys()),
+            expected_waveform)
+        self.assertEqual(list(obj.log_data.keys()),
+                         ['TEXT', ('92EB', '25'), ('98AD', '0')])
+        self.assertEqual(len(obj.log_data['TEXT']), 0)
+        self.assertEqual(list(obj.log_data[('92EB', '25')].keys()), ['SOH'])
+        self.assertEqual(len(obj.log_data[('92EB', '25')]['SOH']), 1)
+        self.assertEqual(
+            obj.log_data[('92EB', '25')]['SOH'][0][:100],
+            '\nState of Health  17:150:00:00:00:000   ST: 92EB'
+            '\n150:00:00:00 REF TEK 130'
+            '\r\n150:00:00:00 CPU SOFTWARE')
+        self.assertEqual(list(obj.soh_data.keys()),
+                         [('92EB', '25'), ('98AD', '0')])
+        self.assertEqual(sorted(list(obj.soh_data[('92EB', '25')].keys())),
+                         sorted(expected_soh))
+        self.assertEqual(list(obj.gaps.keys()),
+                         [('92EB', '25'), ('98AD', '0')])
+        self.assertEqual(obj.gaps[('92EB', '25')], [])
+        self.assertEqual(obj.gaps[('98AD', '0')],
+                         [[1648493999.64, 1648508400.64]])