def start_thread_worker_send(self,
                                 priority=QtCore.QThread.InheritPriority):
        """Start running the event loop of the worker thread.

        Args:
            priority (PyQt5.QtCore.QThread.Priority, optional, default=
                      QtCore.QThread.InheritPriority):
                By default, the 'worker_send' thread runs in the operating system
                at the same thread priority as the main/GUI thread. You can
                change to higher priority by setting 'priority' to, e.g.,
                'QtCore.QThread.TimeCriticalPriority'. Be aware that this is
                resource heavy, so use sparingly.

        Returns True when successful, False otherwise.
        """
        if hasattr(self, 'thread_send'):
            if self.thread_send is not None:
                self.thread_send.start(priority)
                return True
            else:
                print("Worker_send %s: Can't start thread because device is "
                      "not alive." % self.dev.name)
                return False
        else:
            pft("Worker_send %s: Can't start thread because it does not exist. "
                "Did you forget to call 'create_worker_send' first?" %
                self.dev.name)
            return False
示例#2
0
    def query(self, msg_str):
        """ Try to query the device.

        Args:
            msg_str (string): Message to be sent.

        Returns:
            success (bool): True if the message was sent and a reply was
                received successfully, False otherwise.
            ans_str (string): Reply received from the device. [numpy.nan] if
                unsuccessful.
        """
        success = False
        ans_str = np.nan

        if not self.is_alive:
            print("ERROR: Device is not connected yet or already closed.")
        else:
            try:
                ans_str = self.device.query(msg_str)
            except visa.VisaIOError as err:
                # Print error and struggle on
                pft(err)
            except:
                raise
            else:
                ans_str = ans_str.strip()
                success = True

        return (success, ans_str)
示例#3
0
    def write(self, msg_str):
        """Try to write a command to the device.

        Args:
            msg_str (string): Message to be sent.

        Returns: True if the message was sent successfully, False otherwise.
            NOTE: It does not indicate whether the message made sense to the
            device.
        """

        if not self.is_alive:
            print("ERROR: Device is not connected yet or already closed.")
            return False

        try:
            self.device.write(msg_str)
        except visa.VisaIOError as err:
            # Print error and struggle on
            pft(err)
            return False
        except:
            raise

        return True
 def alt_process_jobs_function(self, func, args):
     # Send I/O operation to the device
     try:
         func(*args)
         self.dev.wait_for_OPC()                         # Wait for OPC
     except Exception as err:
         pft(err)
示例#5
0
    def query_ascii_values(self, msg_str="", separator='\t'):
        """Send a message to the serial device and subsequently read the reply.
        Expects a reply from the Arduino in the form of an ASCII string
        containing a list of numeric values. These values will be parsed into a
        list of floats and returned.

        Returns:
            success (bool):
                True if successful, False otherwise.
            ans_floats (list):
                Reply received from the device and parsed into a list of floats.
                [None] if unsuccessful.
        """
        [success, ans_str] = self.query(msg_str)

        if success and not (ans_str == ''):
            try:
                ans_floats = list(map(float, ans_str.split(separator)))
            except ValueError as err:
                # Print error and struggle on
                pft(err, 3)
            except Exception as err:
                pft(err, 3)
                sys.exit(1)
            else:
                return [True, ans_floats]

        return [False, []]
 def create_log(self, start_time, path_log: Path, mode='a'):
     """Open new log file and keep file handle open.
     
     Args:
         start_time:
             Timestamp of the start of recording, usefull to keep track of
             the elapsed time while recording.
         path_log [pathlib.Path]:
             Location of the file to write to.
         mode:
             Mode in which the file is openend, see 'open()' for more
             details. Defaults to 'a'. Most common options:
             'w': Open for writing, truncating the file first
             'a': Open for writing, appending to the end of the file if it
                  exists
     
     Returns: True if successful, False otherwise.
     """
     self.path_log = path_log
     self.start_time = start_time
     self.starting = False
     self.stopping = False
     
     try:
         self.f_log = open(path_log, mode)
     except Exception as err:
         pft(err, 3)
         self.is_recording = False
         return False
     else:            
         self.is_recording = True
         return True
 def attach_device(self, dev):
     """Attach a reference to a 'device' instance with I/O methods.
     """
     if type(self.dev) == self.NoAttachedDevice:
         self.dev = dev
         self.dev.mutex = QtCore.QMutex()
     else:
         pft("Device can be attached only once. Already attached to '%s'." %
             self.dev.name)
示例#8
0
    def query(self, msg_str, timeout_warning_style=1):
        """Send a message to the serial device and subsequently read the reply.

        Args:
            msg_str (str):
                Message to be sent to the serial device.
            timeout_warning_style (int, optional):
                Work-around for the Serial library not throwing an exception
                when read has timed out.
                1 (default): Will print a traceback error message on screen and
                continue.
                2: Will raise the exception again.

        Returns:
            success (bool):
                True if successful, False otherwise.
            ans_str (str):
                Reply received from the device. [None] if unsuccessful.
        """
        success = False
        ans_str = None

        if self.write(msg_str, timeout_warning_style):
            try:
                ans_bytes = self.ser.read_until(self.read_term_char.encode())
            except (serial.SerialTimeoutException,
                    serial.SerialException) as err:
                # Note though: The Serial library does not throw an
                # exception when it actually times out! We will check for
                # zero received bytes as indication for timeout, later.
                pft(err, 3)
            except Exception as err:
                pft(err, 3)
                sys.exit(1)
            else:
                if (len(ans_bytes) == 0):
                    # Received 0 bytes, probably due to a timeout.
                    if timeout_warning_style == 1:
                        pft("Received 0 bytes. Read probably timed out.", 3)
                    elif timeout_warning_style == 2:
                        raise (serial.SerialTimeoutException)
                else:
                    try:
                        ans_str = ans_bytes.decode('utf8').strip()
                    except UnicodeDecodeError as err:
                        # Print error and struggle on
                        pft(err, 3)
                    except Exception as err:
                        pft(err, 3)
                        sys.exit(1)
                    else:
                        success = True

        return [success, ans_str]
 def write(self, data):
     """
     Returns: True if successful, False otherwise.
     """
     try:
         self.f_log.write(data)
     except Exception as err:
         pft(err, 3)
         return False
     else:
         return True
def my_Arduino_DAQ_update():
    # Date-time keeping
    global cur_date_time, str_cur_date, str_cur_time
    cur_date_time = QDateTime.currentDateTime()
    str_cur_date = cur_date_time.toString("dd-MM-yyyy")
    str_cur_time = cur_date_time.toString("HH:mm:ss")

    # Query the Arduino for its state
    [success, tmp_state] = ard.query_ascii_values("?", separator='\t')
    if not (success):
        dprint("'%s' reports IOError @ %s %s" %
               (ard.name, str_cur_date, str_cur_time))
        return False

    # Parse readings into separate state variables
    try:
        [state.time, state.reading_1, state.yaw, state.pitch,
         state.roll] = tmp_state
    except Exception as err:
        pft(err, 3)
        dprint("'%s' reports IOError @ %s %s" %
               (ard.name, str_cur_date, str_cur_time))
        return False

    # Use Arduino time or PC time?
    # Arduino time is more accurate, but rolls over ~49 days for a 32 bit timer.
    use_PC_time = True
    if use_PC_time: state.time = cur_date_time.toMSecsSinceEpoch()

    # Add readings to chart histories
    window.CH_1.add_new_reading(state.time, state.reading_1 - state.tare_value)
    window.CH_yaw.add_new_reading(state.time, state.yaw)
    window.CH_pitch.add_new_reading(state.time, state.pitch)
    window.CH_roll.add_new_reading(state.time, state.roll)

    # Logging to file
    if file_logger.starting:
        fn_log = cur_date_time.toString("yyMMdd_HHmmss") + ".txt"
        if file_logger.create_log(state.time, fn_log, mode='w'):
            file_logger.signal_set_recording_text.emit("Recording to file: " +
                                                       fn_log)
            file_logger.write("elapsed [s]\treading_1\n")

    if file_logger.stopping:
        file_logger.signal_set_recording_text.emit(
            "Click to start recording to file")
        file_logger.close_log()

    if file_logger.is_recording:
        log_elapsed_time = (state.time - file_logger.start_time) / 1e3  # [sec]
        file_logger.write("%.3f\t%.4f\n" % (log_elapsed_time, state.reading_1))

    return True
 def alt_process_jobs_function(self, func, args):
     if (func == "signal_GUI_input_field_update"):
         # Special instruction
         self.signal_GUI_input_field_update.emit(*args)
     else:
         # Default job processing:
         # Send I/O operation to the device
         try:
             func(*args)
             self.dev.wait_for_OPC()
         except Exception as err:
             pft(err)
        def run(self):
            if self.DEBUG:
                dprint(
                    "Worker_send %s run : thread %s" %
                    (self.dev.name, curThreadName()), self.DEBUG_color)

            while self.running:
                locker_worker = QtCore.QMutexLocker(self.mutex)

                if self.DEBUG:
                    dprint(
                        "Worker_send %s: waiting for trigger" % self.dev.name,
                        self.DEBUG_color)
                self.qwc.wait(self.mutex)
                if self.DEBUG:
                    dprint("Worker_send %s: trigger received" % self.dev.name,
                           self.DEBUG_color)
                """Process all jobs until the queue is empty. We must iterate 2
                times because we use a sentinel in a FIFO queue. First iter
                removes the old sentinel. Second iter processes the remaining
                queue items and will put back a new sentinel again.
                """
                for i in range(2):
                    for job in iter(self.queue.get_nowait, self.sentinel):
                        ard = job[0]
                        func = ard.write
                        args = job[1:]

                        if self.DEBUG:
                            dprint(
                                "Worker_send %s: %s %s" %
                                (ard.name, func.__name__, args),
                                self.DEBUG_color)

                        # Send I/O operation to the device
                        locker = QtCore.QMutexLocker(ard.mutex)
                        try:
                            func(*args)
                        except Exception as err:
                            pft(err)
                        locker.unlock()

                    # Put sentinel back in
                    self.queue.put(self.sentinel)

                locker_worker.unlock()

            if self.DEBUG:
                dprint("Worker_send %s: done running" % self.dev.name,
                       self.DEBUG_color)
 def alt_process_jobs_function(self, func, args):
     if (func == "signal_GUI_alarm_values_update"):
         # Special instruction
         self.signal_GUI_alarm_values_update.emit()
     elif (func == "signal_GUI_PID_values_update"):
         # Special instruction
         self.signal_GUI_PID_values_update.emit()
     else:
         # Default job processing:
         # Send I/O operation to the device
         try:
             func(*args)
         except Exception as err:
             pft(err)
示例#14
0
    def query(self, msg_str):
        """Send a command to the serial device and subsequently read the reply.

        Args:
            msg_str (str): Message to be sent to the serial device.

        Returns:
            success (bool): True if successful, False otherwise.
            ans_str (str) : Reply received from the device. [None] if
                            unsuccessful.
        """
        success = False
        ans_str = None

        if not self.is_alive:
            pft("Device is not connected yet or already closed.", 3)
        else:
            try:
                # Send command string to the device as bytes
                self.ser.write((msg_str + TERM_CHAR).encode())
            except (serial.SerialTimeoutException,
                    serial.SerialException) as err:
                # Print error and struggle on
                pft(err, 3)
            except Exception as err:
                pft(err, 3)
                sys.exit(0)
            else:
                try:
                    ans_bytes = self.ser.read_until(TERM_CHAR.encode())
                except (serial.SerialTimeoutException,
                        serial.SerialException) as err:
                    pft(err, 3)
                except Exception as err:
                    pft(err, 3)
                    sys.exit(0)
                else:
                    ans_str = ans_bytes.decode('utf8').strip()
                    if ans_str[0] == '>':
                        # Successfull operation without meaningfull reply
                        success = True
                    elif ans_str[0] == '!':
                        # Error reply
                        print("COMPAX3 COMMUNICATION ERROR: " + ans_str)
                    else:
                        # Successfull operation with meaningfull reply
                        success = True

        return [success, ans_str]
示例#15
0
    def query(self, msg_str):
        """Send a command to the serial device and subsequently read the reply.

        Args:
            msg_str (str): Message to be sent to the serial device.

        Returns:
            success (bool): True if successful, False otherwise.
            ans_str (str): Reply received from the device. None if unsuccessful.
        """
        success = False
        ans_str = None

        if not self.is_alive:
            print("ERROR: Device is not connected yet or already closed.")
        else:
            try:
                # Send command string to the device as bytes
                self.ser.write(msg_str.replace(' ', '').encode())
            except (serial.SerialTimeoutException,
                    serial.SerialException) as err:
                # Print error and struggle on
                pft(err, 3)
            except:
                raise
                sys.exit(0)
            else:
                try:
                    # Read all bytes in the line that is terminated with a
                    # newline character or until time-out has occured
                    ans_bytes = self.ser.readline()
                except (serial.SerialTimeoutException,
                        serial.SerialException) as err:
                    pft(err, 3)
                except:
                    raise
                    sys.exit(0)
                else:
                    # Convert bytes into string and remove termination chars and
                    # spaces
                    ans_str = ans_bytes.decode().strip()
                    success = True

        return [success, ans_str]
    def alt_process_jobs_function(self, func, args):
        # Send I/O operation to the device
        try:
            func(*args)
        except Exception as err:
            pft(err)

        # Check to signal auto open or close of an optional peripheral valve
        if func == self.dev.send_setpoint:
            if args[0] == 0:
                # Setpoint was set to 0 --> signal auto close
                self.dev.valve_auto_close_briefly_prevent = False
                self.signal_valve_auto_close.emit()
            else:
                # Flow enabled --> start deadtime on auto close
                #              --> signal auto open
                self.dev.valve_auto_close_briefly_prevent = True
                self.dev.valve_auto_close_start_deadtime = \
                    QDateTime.currentDateTime()
                self.dev.state.prev_flow_rate = -1  # Necessary reset
                self.signal_valve_auto_open.emit()
示例#17
0
    def write(self, msg_str, timeout_warning_style=1):
        """Send a message to the serial device.

        Args:
            msg_str (str):
                String to be sent to the serial device.
            timeout_warning_style (int, optional):
                1 (default): Will print a traceback error message on screen and
                continue.
                2: Will raise the exception again.

        Returns: True if successful, False otherwise.
        """
        success = False

        if not self.is_alive:
            pft("Device is not connected yet or already closed.", 3)
        else:
            try:
                self.ser.write((msg_str + self.write_term_char).encode())
            except (serial.SerialTimeoutException,
                    serial.SerialException) as err:
                if timeout_warning_style == 1:
                    pft(err, 3)
                elif timeout_warning_style == 2:
                    raise (err)
            except Exception as err:
                pft(err, 3)
                sys.exit(1)
            else:
                success = True

        return success
    def parse_data_bytes(self, ans_bytes):
        """Parse the data bytes.

        The manual states:
            data_bytes[0] : the qualifier byte
              b.0 to b.3 indicates unit of measure index
              b.4 to b.7 indicates precision of measurement
            data_bytes[1:]: value

        Returns:
            value (float): The decoded float value. [numpy.nan] if unsuccessful.
            uom     (int): Unit of measure index. [numpy.nan] if unsuccessful.
        """
        value = np.nan
        uom = np.nan
        try:
            nn = ans_bytes[4]  # Number of data bytes to follow
            data_bytes = ans_bytes[5:5 + nn]
            pom = data_bytes[0] >> 4  # Precision of measurement
            uom = data_bytes[0] % 0x10  # Unit of measure index
            int_value = int.from_bytes(data_bytes[1:],
                                       byteorder='big',
                                       signed=False)
        except Exception as err:
            pft(err, 3)
        else:
            if pom == 0:
                value = int_value
            elif pom == 1:
                value = int_value * 0.1
            elif pom == 2:
                value = int_value * 0.01
            elif pom == 3:
                value = int_value * 0.001
            elif pom == 4:
                value = int_value * 0.0001

        return [value, uom]
示例#19
0
    def __init__(self,
                 trav_horz: Compax3_traverse=None,
                 trav_vert: Compax3_traverse=None,
                 parent=None, **kwargs):
        super().__init__(parent, **kwargs)

        if not (isinstance(trav_horz, Compax3_traverse) or trav_horz is None):
            pft("Argument 'trav_horz' is of a wrong type.", 3)
            sys.exit(1)
        if not (isinstance(trav_vert, Compax3_traverse) or trav_vert is None):
            pft("Argument 'trav_vert' is of a wrong type.", 3)
            sys.exit(1)

        self.listening_to_arrow_keys = False
        self.trav_horz = trav_horz
        self.trav_vert = trav_vert
        self.horz_pos  = np.nan     # [mm]
        self.vert_pos  = np.nan     # [mm]
        self.step_size = np.nan     # [mm]

        self.create_GUI()
        self.connect_signals_to_slots()
        self.process_editingFinished_qled_step_size()
    def query(self, msg_bytes):
        """Send a command to the serial device and subsequently read the reply.

        Args:
            msg_bytes (bytes): Message to be sent to the serial device.

        Returns:
            success (bool): True if successful, False otherwise.
            ans_bytes (bytes): Reply received from the device. [numpy.nan] if
                unsuccessful.

        TO DO: force ser.flush after ser.write
        TO DO: implement ser.readline instead of sleep() & inWaiting
        """
        success = False
        ans_bytes = np.nan

        if not self.is_alive:
            pft("Device is not connected yet or already closed.", 3)
            return [success, ans_bytes]

        try:
            # Send command string to the device as bytes
            self.ser.write(msg_bytes)
        except (serial.SerialTimeoutException, serial.SerialException) as err:
            pft(err, 3)
        except Exception as err:
            pft(err, 3)
            sys.exit(0)
        else:
            # Wait for the incoming buffer to fill with the device's complete
            # reply. Note: The chiller does not use an EOL character to signal
            # the end of line, hence we can't use ser.readline().
            time.sleep(RS232_SLEEP)

            try:
                # Read all the bytes waiting in the in-buffer
                ans_bytes = self.ser.read(self.ser.inWaiting())
                #print_as_hex(ans_bytes)                     # debug info
            except (serial.SerialTimeoutException,
                    serial.SerialException) as err:
                pft(err, 3)
            except Exception as err:
                pft(err, 3)
                sys.exit(0)
            else:
                # Check for errors reported by a possibly connected ThermoFlex
                # chiller
                if (len(ans_bytes) >= 4) and ans_bytes[3] == 0x0f:
                    # Error reported by chiller
                    if ans_bytes[5] == 1:
                        pft("Bad command received by chiller", 3)
                    elif ans_bytes[5] == 2:
                        pft("Bad data received by chiller", 3)
                    elif ans_bytes[5] == 3:
                        pft("Bad checksum received by chiller", 3)
                else:
                    # We got a reply back from /a/ device, not necessarily a
                    # ThermoFlex chiller.
                    success = True

        return [success, ans_bytes]
        def run(self):
            if self.DEBUG:
                dprint(
                    "Worker_send %s run : thread %s" %
                    (self.dev.name, curThreadName()), self.DEBUG_color)

            while self.running:
                locker_wait = QtCore.QMutexLocker(self.mutex_wait)

                if self.DEBUG:
                    dprint(
                        "Worker_send %s: waiting for trigger" % self.dev.name,
                        self.DEBUG_color)

                self.qwc.wait(self.mutex_wait)
                locker = QtCore.QMutexLocker(self.dev.mutex)
                self.update_counter += 1

                if self.DEBUG:
                    dprint(
                        "Worker_send %s: lock %i" %
                        (self.dev.name, self.update_counter), self.DEBUG_color)
                """Process all jobs until the queue is empty. We must iterate 2
                times because we use a sentinel in a FIFO queue. First iter
                removes the old sentinel. Second iter processes the remaining
                queue items and will put back a new sentinel again.
                """
                for i in range(2):
                    for job in iter(self.queue.get_nowait, self.sentinel):
                        func = job[0]
                        args = job[1:]

                        if self.DEBUG:
                            if type(func) == str:
                                dprint(
                                    "Worker_send %s: %s %s" %
                                    (self.dev.name, func, args),
                                    self.DEBUG_color)
                            else:
                                dprint(
                                    "Worker_send %s: %s %s" %
                                    (self.dev.name, func.__name__, args),
                                    self.DEBUG_color)

                        if self.alt_process_jobs_function is None:
                            # Default job processing:
                            # Send I/O operation to the device
                            try:
                                func(*args)
                            except Exception as err:
                                pft(err)
                        else:
                            # User-supplied job processing
                            self.alt_process_jobs_function(func, args)

                    # Put sentinel back in
                    self.queue.put(self.sentinel)

                if self.DEBUG:
                    dprint("Worker_send %s: unlocked" % self.dev.name,
                           self.DEBUG_color)

                locker.unlock()
                locker_wait.unlock()

            if self.DEBUG:
                dprint("Worker_send %s: done running" % self.dev.name,
                       self.DEBUG_color)