コード例 #1
0
 def save(self):
     """
     Saves the recorded file to the desired location.
     :return:
     """
     Log.i(TAG, "Clicked save")
     if len(self.session_files) > 0:
         save_path = PopUp.save_file(self)
         if save_path != '':
             Log.i(
                 TAG, "Saving {} at {}".format(self.session_files[-1],
                                               save_path))
             shutil.copyfile(self.session_files[-1], save_path)
             Log.i(
                 TAG, "Saved {} at {}".format(self.session_files[-1],
                                              save_path))
             self.ui.tBrowser_Log.append(
                 "Saved data at {}.".format(save_path))
         else:
             Log.i(TAG, "No file name entered, so file wasn't saved.")
     else:
         Log.i(TAG, "No signal files in current session.")
         self.ui.tBrowser_Log.append("Terminated save due to an error.")
         PopUp.warning(self, Constants.app_title,
                       "Record signal before saving.")
コード例 #2
0
 def stop(self):
     """
     Signals the process to stop acquiring data.
     :return:
     """
     Log.i(TAG, "Process finishing...")
     self._exit.set()
コード例 #3
0
    def start(self):
        """
        Starts all processes, based on configuration given in constructor.
        :return:
        """
        self.reset_buffers(self._samples)
        if self._export:
            self._csv_process = CSVProcess(path=self._path)
            self._parser_process = ParserProcess(
                self._queue, store_reference=self._csv_process)
            self._filepath = self._csv_process.get_filepath()
        else:
            self._parser_process = ParserProcess(self._queue)

        if self._source == SourceType.serial:
            self._acquisition_process = SerialProcess(self._parser_process)
        if self._acquisition_process.open(port=self._port, speed=self._speed):
            self._parser_process.start()
            if self._export:
                self._csv_process.start()
            self._acquisition_process.start()
            return True
        else:
            Log.i(TAG, "Port is not available")
            return False
コード例 #4
0
 def set_user_log_level(self):
     """
     Sets the user specified log level.
     :return:
     """
     if self._parser is not None:
         self._parse_log_level()
     else:
         Log.w(TAG, "Parser was not created !")
         return None
コード例 #5
0
 def __init__(self, parser_process):
     """
     Initialises values for process.
     :param parser_process: Reference to a ParserProcess instance.
     :type parser_process: ParserProcess.
     """
     multiprocessing.Process.__init__(self)
     self._exit = multiprocessing.Event()
     self._parser = parser_process
     self._serial = serial.Serial()
     Log.i(TAG, "Process ready")
コード例 #6
0
 def _update_sample_size(self):
     """
     Updates the sample size of the plot.
     This function is connected to the valueChanged signal of the sample Spin Box.
     :return:
     """
     if self.worker is not None:
         Log.i(TAG, "Changing sample size")
         self.worker.reset_buffers(self.ui.sBox_Samples.value())
         self.ui.tBrowser_Log.append("Updated sample size: {}.".format(
             self.ui.sBox_Samples.value()))
コード例 #7
0
 def closeEvent(self, evnt):
     """
     Overrides the QTCloseEvent.
     This function is connected to the clicked signal of the close button of the window.
     :param evnt: QT evnt.
     :return:
     """
     if self.worker.is_running():
         Log.i(TAG, "Window closed without stopping capture, stopping it")
         self.ui.tBrowser_Log.append("Closing window.")
         self.stop()
コード例 #8
0
 def help(self):
     """
     Opens the message for the program.
     This function is connected to the clicked signal of the Help button.
     :return:
     """
     Log.i(TAG, "Clicked help")
     PopUp.message(
         self, Constants.app_title + " Instructions",
         "View Options:\n     - Start: starts data stream\n     - Stop: stops data stream\n\nRecord Options\n     - n Seconds: enter the desired time length\n     - Record: starts recording data\n     - Save: save recorded data\n\nBCI/Plot Options\n     - Ports: select the serial device port\n     - Baud Rate: select the baud rate\n     - n Samples: enter the desired samples #"
     )
コード例 #9
0
 def _update_seconds(self):
     """
     Updates the seconds for recording.
     This function is connected to the valueChanged signal of the sample Spin Box.
     :return:
     """
     if self.worker is not None:
         Log.i(TAG, "Changing recording length")
         self.worker.reset_buffers(self.ui.sBox_Seconds.value())
         self.ui.tBrowser_Log.append(
             "Updated recording length: {} seconds.".format(
                 self.ui.sBox_Seconds.value()))
コード例 #10
0
 def run(self):
     """
     Process will monitor the internal buffer to parse raw data and distribute to graph and storage, if needed.
     The process will loop again after timeout if more data is available.
     :return:
     """
     Log.d(TAG, "Process starting...")
     while not self._exit.is_set():
         self._consume_queue()
         sleep(self._consumer_timeout)
     # last check on the queue to completely remove data.
     self._consume_queue()
     Log.d(TAG, "Process finished")
コード例 #11
0
 def get_source_speeds(source):
     """
     Gets the available speeds for specified source.
     :param source: Source to get available speeds.
     :type source: SourceType.
     :return: List of available speeds.
     :rtype: str list.
     """
     if source == SourceType.serial:
         return SerialProcess.get_speeds()
     else:
         Log.w(TAG, "Unknown source selected")
         return None
コード例 #12
0
 def reset_buffers(self, samples):
     """
     Setup/clear the internal buffers.
     :param samples: Number of samples for the buffers.
     :type samples: int.
     :return:
     """
     self._data_buffers = []
     for tmp in Constants.plot_colors:
         self._data_buffers.append(RingBuffer(samples))
     self._time_buffer = RingBuffer(samples)
     while not self._queue.empty():
         self._queue.get()
     Log.i(TAG, "Buffers cleared")
コード例 #13
0
 def _update_baud(self):
     """
     Updates the baud rate.
     :return:
     """
     if self.ui.cBox_BaudRate.currentText() == "Baud Rate":
         Log.i(TAG, "No baud rate selected")
         self.ui.tBrowser_Log.append("No baud rate was selected.")
     else:
         Log.i(
             TAG, "Updated baud rate: {}".format(
                 self.ui.cBox_BaudRate.currentText()))
         self.ui.tBrowser_Log.append("Updated baud rate: {}.".format(
             self.ui.cBox_BaudRate.currentText()))
コード例 #14
0
ファイル: app.py プロジェクト: chanhakim/mbci_lab
 def run(self):
     if Architecture.is_python_version(MinimalPython.major,
                                       minor=MinimalPython.minor):
         Log.i(TAG, "Starting mbci_lab")
         win = mainWindow.MainWindow(samples=self._args.get_user_samples())
         win.setWindowTitle("{} - {}".format(Constants.app_title,
                                             Constants.app_version))
         win.show()
         self._app.exec()
         Log.i(TAG, "Finishing mbci_lab\n")
         win.close()
     else:
         self._fail()
     self.close()
コード例 #15
0
 def stop(self):
     """
     Stops the acquisition of the selected serial port.
     This function is connected to the clicked signal of the Stop button.
     :return:
     """
     Log.i(TAG, "Clicked stop")
     self._timer_plot.stop()
     self._enable_ui(True)
     self.worker.stop()
     self.session_files.append(self.worker.get_filepath())
     if self._isrecording == True:
         self._isrecording = False
         self.save()
     self.ui.tBrowser_Log.append("Stopped data stream.")
コード例 #16
0
 def get_ports():
     """
     Gets a list of the available serial ports.
     :return: List of available serial ports.
     :rtype: str list.
     """
     if Architecture.get_os() is OSType.macosx:
         import glob
         return glob.glob("/dev/tty.*")
     else:
         found_ports = []
         for port in list(list_ports.comports()):
             Log.d(TAG, "found device {}".format(port))
             found_ports.append(port.device)
         return found_ports
コード例 #17
0
ファイル: Csv.py プロジェクト: chanhakim/mbci_lab
 def run(self):
     """
     Process will monitor the internal buffer to write data to the export file,
     and the process will loop again after timeout if more data is available.
     :return:
     """
     Log.i(TAG, "Process starting...")
     self._csv = csv.writer(self._file,
                            delimiter=Constants.csv_delimiter,
                            quoting=csv.QUOTE_MINIMAL)
     self._csv.writerow(['time', 'signal'])
     while not self._exit.is_set():
         self._consume_queue()
         sleep(self._timeout)
     # last check on the queue to completely remove data.
     self._consume_queue()
     Log.i(TAG, "Process finished")
     self._file.close()
コード例 #18
0
ファイル: Csv.py プロジェクト: chanhakim/mbci_lab
 def _create_file(filename, path=None, extension=Constants.csv_extension):
     """
     Creates the file to export the data.
     :param filename: Name of the file where data will be exported.
     :type filename: str.
     :param path: Path where data file will be saved.
     :type path: str.
     :param extension: Extension to give to the export file.
     :type extension: str.
     :return: Reference to the export file.
     """
     FileManager.create_dir(path)
     full_path = FileManager.create_file(filename,
                                         extension=extension,
                                         path=os.path.abspath(path))
     if not FileManager.file_exists(full_path):
         Log.i(TAG, "Storing in {}".format(full_path))
         return open(full_path, "a", newline=''), full_path
     return None
コード例 #19
0
 def start(self):
     """
     Starts the acquisition of the selected serial port.
     This function is connected to the clicked signal of the Start button.
     :return:
     """
     Log.i(TAG, "Clicked start")
     self.ui.tBrowser_Log.append("Started data stream.")
     port_id, baud_rate = self.ui.cBox_Port.currentText(
     ), self.ui.cBox_BaudRate.currentText()
     if (port_id != "Ports (Refresh)") and (baud_rate != "Baud Rate"):
         self.worker = Worker(port=self.ui.cBox_Port.currentText(),
                              speed=int(
                                  self.ui.cBox_BaudRate.currentText()),
                              samples=self.ui.sBox_Samples.value())
         if self.worker.start():
             self._timer_plot.start(Constants.plot_update_ms)
             self._enable_ui(False)
         else:
             Log.i(TAG, "Port is not available")
             PopUp.warning(
                 self, Constants.app_title,
                 "Selected port \"{}\" is not available".format(
                     self.ui.cBox_Port.currentText()))
     else:
         Log.i(TAG, "No port or baud rate was selected")
         self.ui.tBrowser_Log.append("Terminated data stream due to error.")
         PopUp.warning(self, Constants.app_title,
                       "Select a port and baud rate")
コード例 #20
0
 def record(self):
     """
     Starts recording signal from the selected port. Function
     is connected to the record button
     :return:
     """
     Log.i(TAG, "Clicked record")
     self.ui.tBrowser_Log.append("Started recording data.")
     self._isrecording = True
     port_id, baud_rate = self.ui.cBox_Port.currentText(
     ), self.ui.cBox_BaudRate.currentText()
     if (port_id != "Ports (Refresh)") and (baud_rate != "Baud Rate"):
         self.worker = Worker(port=self.ui.cBox_Port.currentText(),
                              speed=int(
                                  self.ui.cBox_BaudRate.currentText()),
                              samples=self.ui.sBox_Samples.value(),
                              export_enabled=True)
         if self.worker.start():
             self._timer_plot.start(Constants.plot_update_ms)
             self._enable_ui(False)
         else:
             Log.i(TAG, "Port is not available")
             PopUp.warning(
                 self, Constants.app_title,
                 "Selected port \"{}\" is not available".format(
                     self.ui.cBox_Port.currentText()))
             return None
     else:
         Log.i(TAG, "No port or baud rate was selected")
         self.ui.tBrowser_Log.append(
             "Terminated data recording due to error.")
         PopUp.warning(self, Constants.app_title,
                       "Select a port and baud rate")
         return None
コード例 #21
0
 def _parse_csv(self, time, line):
     """
     Parses incoming data and distributes to external processes.
     :param time: Timestamp.
     :type time: float.
     :param line: Raw data coming from acquisition process.
     :type line: basestring.
     :return:
     """
     if len(line) > 0:
         try:
             if type(line) == bytes:
                 values = line.decode("UTF-8").split(self._split)
             elif type(line) == str:
                 values = line.split(self._split)
             else:
                 raise TypeError
             values = [float(v) for v in values]
             Log.d(TAG, values)
             self._out_queue.put((time, values))
             if self._store_reference is not None:
                 self._store_reference.add(time, values)
         except ValueError:
             Log.w(TAG,
                   "Can't convert to float. Raw: {}".format(line.strip()))
         except AttributeError:
             Log.w(
                 TAG, "Attribute error on type ({}). Raw: {}".format(
                     type(line), line.strip()))
コード例 #22
0
    def _update_port(self):
        """
        Updates the source and depending boxes on change.
        This function is connected to the indexValueChanged signal of the Source ComboBox.
        :return:
        """
        tmp = self.ui.cBox_Port.currentText()
        if tmp == "Ports (Refresh)":
            Log.i(TAG, "Scanning source serial")
            # clear boxes before adding new
            self.ui.cBox_Port.clear()

            ports = self.worker.get_source_ports(SourceType.serial)
            ports.insert(0, "Ports (Refresh)")

            if ports is not None:
                self.ui.cBox_Port.addItems(ports)
            self.ui.tBrowser_Log.append("Refreshed ports.")
        else:
            Log.i(TAG, "Serial port {} was selected".format(tmp))
            self.ui.tBrowser_Log.append("Selected port: {}".format(
                self.ui.cBox_Port.currentText()))
コード例 #23
0
ファイル: Csv.py プロジェクト: chanhakim/mbci_lab
    def __init__(self, filename=None, path=None, timeout=0.5):
        """
        Sets up the file to export the data as CSV.
        If filename is not specified, a default name based on time will be used.
        :param filename: Name of the file where data will be exported.
        :type filename: str.
        :param path: Path where data file will be saved.
        :type path: str.
        :param timeout: Time to wait after emptying the internal buffer before next write.
        :type timeout: float.
        """
        multiprocessing.Process.__init__(self)
        self._exit = multiprocessing.Event()
        self._store_queue = multiprocessing.Queue()
        self._csv = None
        self._file = None
        self._timeout = timeout

        if filename is None:
            filename = 'temp_{}'.format(
                strftime(Constants.csv_default_filename, gmtime()))
        self._file, self._filepath = self._create_file(filename, path=path)
        Log.i(TAG, "Process ready")
コード例 #24
0
    def __init__(self,
                 data_queue,
                 store_reference=None,
                 split=Constants.csv_delimiter,
                 consumer_timeout=Constants.parser_timeout_ms):
        """

        :param data_queue: Reference to Queue where processed data will be put.
        :type data_queue: multiprocessing Queue.
        :param store_reference: Reference to CSVProcess instance, if needed.
        :type store_reference: CSVProcess (multiprocessing.Process)
        :param split: Delimiter in incoming data.
        :type split: str.
        :param consumer_timeout: Time to wait after emptying the internal buffer before next parsing.
        :type consumer_timeout: float.
        """
        multiprocessing.Process.__init__(self)
        self._exit = multiprocessing.Event()
        self._in_queue = multiprocessing.Queue()
        self._out_queue = data_queue
        self._consumer_timeout = consumer_timeout
        self._split = split
        self._store_reference = store_reference
        Log.d(TAG, "Process ready")
コード例 #25
0
 def run(self):
     """
     Reads the serial port expecting CSV until a stop call is made.
     The expected format is comma (",") separated values, and a new line (CRLF or LF) as a new row.
     While running, it will parse CSV data convert each value to float and added to a queue.
     If incoming data from serial port can't be converted to float, that data will be discarded.
     :return:
     """
     Log.i(TAG, "Process starting...")
     if self._is_port_available(self._serial.port):
         if not self._serial.isOpen():
             self._serial.open()
             Log.i(TAG, "Port opened")
             timestamp = time()
             while not self._exit.is_set():
                 self._parser.add(
                     [time() - timestamp,
                      self._serial.readline()])
             Log.i(TAG, "Process finished")
             self._serial.close()
         else:
             Log.w(TAG, "Port is not opened")
     else:
         Log.w(TAG, "Port is not available")
コード例 #26
0
ファイル: app.py プロジェクト: chanhakim/mbci_lab
 def _fail():
     txt = str("mbci_lab requires Python {}.{} to run".format(
         MinimalPython.major, MinimalPython.minor))
     Log.e(TAG, txt)
コード例 #27
0
ファイル: app.py プロジェクト: chanhakim/mbci_lab
 def close(self):
     self._app.exit()
     Log.close()
     sys.exit()