def __init__(self, parent=None):
        super(PyClockSetup, self).__init__()

        self.serial = QSerialPort(self)
        uic.loadUi('pyclocksetup.ui', self)
        self.show()

        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updateTime)
        self.timer.start(1000)

        self.serial = QSerialPort(self)
        self.cp.colorChanged.connect(self.changeColor)
        self.connectButton.clicked.connect(self.serialConnect)
        self.setClockButton.clicked.connect(self.setClock)
        self.blinkingDots.toggled.connect(self.setBlinkingDots)
        self.leadingZero.toggled.connect(self.setLeadingZero)
        self.autoBrightness.toggled.connect(self.setAutoBrightness)
        self.segmentTest.toggled.connect(self.setSegmentTest)
        self.brightnessSlider.valueChanged.connect(self.changeBrightness)

        self.colorLabel.setStyleSheet('QLabel {background-color: #ffffff; }')

        availablePorts = QSerialPortInfo.availablePorts()
        for port in availablePorts:
            self.serialPorts.addItem(port.portName())
Exemple #2
0
 def CreateItems(self):
     # Qt 串口类
     self.com = QSerialPort()
     # Qt 定时器类
     self.timer = QTimer(self)  #初始化一个定时器
     self.timer.timeout.connect(self.ShowTime)  #计时结束调用operate()方法
     self.timer.start(100)  #设置计时间隔 100ms 并启动
Exemple #3
0
 def __init__(self, *args, **kwds):
     super(Com_port, self).__init__(kwds.pop('parent'))
     self.ser = QSerialPort(kwds.pop('port'))
     self.ser.open(QIODevice.ReadWrite)
     self.ser.setBaudRate(kwds.pop('baudrate'))
     self.ser.readyRead.connect(self.on_serial_read)
     print("Com port " + self.ser.portName() + ' ready.')
Exemple #4
0
class Weigher():
    def __init__(self, port_name=None, baud_rate=None,
                 data_bits=None, stop_bits=None):
        # Read config
        config = read_config()[port_name]
        self.port_name = config['port_name']
        self.baud_rate = config['baud_rate']
        self.data_bits = config['data_bits']
        self.stop_bits = config['stop_bits']

        # Initial
        self.weigher = QSerialPort()  # It is the subclass of the QIODevice class;
        self.weigher.setPortName(self.port_name)  # passing name such as 'COM1'
        self.weigher.setBaudRate(int(self.baud_rate))
        self.weigher.setDataBits(QSerialPort.DataBits(int(self.data_bits)))
        self.weigher.setStopBits(QSerialPort.StopBits(int(self.stop_bits)))

        # Logging module
        self.mylogging = MyLogging(logger_name='user')
        self.mylogger = self.mylogging.logger

    def read(self):
        if self.weigher.canReadLine():
            ascii_data = self.weigher.readLine()
            data = ascii_data.decode('ascii')
            try:
                # The formate of weigher returns datas.
                weigher_data = float(data[1:-4]) * 1000
                return weigher_data
            except BaseException as e:
                self.mylogger.error(e)
Exemple #5
0
    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.serial = QSerialPort(self)
        self.timer = QtCore.QElapsedTimer()

        self.graphInit()
        self.getAvaliablePorts()

        self.ui.pushButton_Get.clicked.connect(self.getOnce_slot)
        self.ui.pushButton_Start.clicked.connect(self.start_slot)
        self.ui.pushButton_Stop.clicked.connect(self.stop_slot)

        self.serial.readyRead.connect(self.serialRead_slot)
        self.data_isReady_signal.connect(self.plotUpdate)
        self.get_data_signal.connect(self.getOnce_slot)

        average = []
        for i in range(1, 10):
            average.append(str(i))
        for average_ in average:
            entry = QAction(average_, self)
            self.ui.menuAverage.addAction(entry)
            entry.triggered.connect(lambda Val, average_to_set=average_: self.
                                    average_set(average_to_set))
Exemple #6
0
    def slot_connect(self):
        self.serialport_name = self.qcb_ports.currentText()
        self.serialport = QSerialPort()
        self.serialport.setPortName(self.serialport_name)
        self.serialport.setBaudRate(
            self.baudrates[self.qcb_baudrates.currentText()])
        self.serialport.setDataBits(
            self.databits[self.qcb_databits.currentText()])
        self.serialport.setParity(
            self.paritybit[self.qcb_paritybit.currentText()])
        self.serialport.setStopBits(
            self.stopbits[self.qcb_stopbits.currentText()])
        self.serialport.setFlowControl(QSerialPort.NoFlowControl)
        # self.serialport.close()
        self.serialport.open(QIODevice.ReadWrite)
        if self.serialport.isOpen():
            self.serialport.readyRead.connect(self.ready_read)
            self.qpb_connect_disconnect.setText("Disconnect")
            self.qpb_connect_disconnect.disconnect()
            self.qpb_connect_disconnect.clicked.connect(self.slot_disconnect)
            if self.fl_log:
                self.logfile = open(self.logfile_location, 'w')

            self.qcb_ports.setDisabled(True)
            self.qcb_baudrates.setDisabled(True)
            self.qcb_databits.setDisabled(True)
            self.qcb_paritybit.setDisabled(True)
            self.qcb_stopbits.setDisabled(True)
            self.qcb_flowcontrol.setDisabled(True)
            self.qpb_refresh.setDisabled(True)
            self.qpb_load_session.setDisabled(True)
    def setupSerialPort(self):
        """
        Процедура установки различных параметров для ком-порта

        """
        self.serial = QSerialPort()
        self.serial.readyRead.connect(self.onDataRecv)

        try:
            settings = cfg.read()
        except Exception as e:
            msg = QMessageBox(self)
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Ошибка при чтении настроек ком-порта")
            msg.setInformativeText(str(e))
            msg.setWindowTitle("Ошибка")
            msg.setDetailedText(traceback.format_exc())
            msg.exec_()
            return

        if len(cfg.VALID_VALUES['port']) == 0:
            self.setSerialStatus("COM-порты не найдены", False)
            return

        elif settings['port'] not in cfg.VALID_VALUES['port']:
            dialog = SerialPortConfigDialog(self)
            dialog.exec_()
            if dialog.okClicked:
                settings = dialog.settings
            else:
                self.setSerialStatus("COM-порт не настроен", False)
            return

        self.setSerialSettings(settings)
        self.startSerial()
Exemple #8
0
    def init(self):

        self.serianame = ''
        self.com = QSerialPort()
        self.cominfo = QSerialPortInfo()
        self.infos = self.cominfo.availablePorts()
        for info in self.infos:
            print("Name:", info.portName())
            print("vendoridentifier:", info.vendorIdentifier())

            # 串口信息认证
            if info.vendorIdentifier() == 6790:
                self.serianame = info.portName()

        self.com.setPortName(self.serianame)
        self.com.setBaudRate(9600)

        # 打开串口
        if self.com.open(QSerialPort.ReadWrite) == False:
            print("open fault")
            return

        # 设置定时函数
        self.readtimer = QTimer()
        self.readtimer.timeout.connect(self.readData)  # 读信号
        self.readtimer.start(200)  # 每200ms读一次数据
 def __init__(self):
     super(SerialProtoParser, self).__init__()
     # Serial port
     self.__serialPort = QSerialPort()
     # Setup Serialport
     # We are using USB serial driver, so the baud rate doesn't matter
     self.__serialPort.setBaudRate(QSerialPort.Baud115200,
                                   QSerialPort.Input)
     self.destroyed.connect(self.close)
     # Get the list of all available serial ports
     portsList = QSerialPortInfo.availablePorts()
     # Only connect to Chibios port
     chibiOsPort = None
     for port in portsList:
         if ("ChibiOS" in port.description()):
             chibiOsPort = port
     if (chibiOsPort is None):
         print("Cannot find chibios based device")
     else:
         # Set the serial port
         self.__serialPort.setPort(chibiOsPort)
         self.__serialPort.setDataBits(QSerialPort.Data8)
         self.__serialPort.setFlowControl(QSerialPort.NoFlowControl)
         self.__serialPort.setParity(QSerialPort.NoParity)
         self.__serialPort.setStopBits(QSerialPort.OneStop)
         # Connect signals and slots
         self.__serialPort.readyRead.connect(self.__onSerialPortReadyRead)
         # Open the device
         self.__serialPort.open(QIODevice.ReadOnly)
 def __init__(self, *args, **kwargs):
     super(Window, self).__init__(*args, **kwargs)
     self.setupUi(self)
     self._serial = QSerialPort(self)  # 用于连接串口的对象
     self._serial.readyRead.connect(self.onReadyRead)  # 绑定数据读取信号
     # 首先获取可用的串口列表
     self.getAvailablePorts()
Exemple #11
0
    def connectSerial(self, port):
        #try:
        self.active_port = QSerialPort(port,
                                       baudRate=QSerialPort.Baud9600,
                                       readyRead=self.receive)
        if not self.active_port.isOpen(
        ):  #Close serial port if it is already open
            if self.active_port.open(
                    QtCore.QIODevice.ReadWrite):  #Open serial connection
                self.active_port.readyRead.connect(self.receive)
                self.active_port.clear()  #Clear buffer of any remaining data
                self.gui.status_dict["COM Port"] = self.getPortInfo(
                    self.active_port)["Port"]
                return True
            else:
                if debug:
                    print("Can't open port1")
        else:
            if debug:
                print("Can't open port2")

    #except: #Return False if unable to establish connection to serial port
        if debug:
            print("Failed to connect to COM port, with QSerialPort Error #" +
                  str(self.active_port.error()))
        self.disconnectSerial()
        return False
Exemple #12
0
    def __init__(self, parent=None):
        super().__init__(parent)

        self.__data = QByteArray()
        self.__serial = QSerialPort()
        self.__timer = QTimer(self)

        for info in QSerialPortInfo.availablePorts():
            if info.description() == "USB-SERIAL CH340":
                self.__serial = QSerialPort(info)
                print(self.__serial.portName())
                break

        self.__serial.readyRead.connect(self.__read_data)
        self.__timer.timeout.connect(self.__timer_update_com)

        self.__temperature = 0
        self.__humidity = 0
        self.__co2 = 0
        self.__tvoc = 0
        self.__pm25 = 0
        self.__pm10 = 0
        self.__o2 = 0

        if self.__serial.open(QIODevice.ReadWrite):
            print("open success")
        else:
            print("open fail")
        self.__auto_save_thread = AutoSave(self)
        self.__auto_save_thread.start()
Exemple #13
0
    def __init__(self):
        super(SerialPort, self).__init__()
        self.ports = []
        self.serialData = ''
        self.commands = {
            'CurveTemporal': '|',
            'GainOffset': ':',
            'Laser': '#',
            'TimeAverage': '&',
            'StopTemporal': '[',
            'StopTechnical': '.',
            'ControlPeris': '*',
            'ControlImpulA': '!',
            'ControlImpulB': '+',
            'BackPeris': '<',
            'StopPeris': '=',
            'ForwardPeris': '>',
            'TimePulsesPumps': '_',
            'VolumePurge': 'a7',
            'PurgeImpulA': '{',
            'PurgeImpulB': '}',
            'IAmAlive': '?',
            'PowerDown': '/'
        }

        self.serialPort = QSerialPort()
Exemple #14
0
    def __init__(self):
        super().__init__()
        self.logger = logging.getLogger('controlpanel')
        l = QVBoxLayout(self)
        b = QPushButton("Gas")
        b.clicked.connect(self.do_go)
        l.addWidget(b)

        b2 = QPushButton("Bremsen")
        b2.clicked.connect(self.do_stop)
        l.addWidget(b2)

        self.motor_panel = MotorDataPanel()
        self.info_panel = InfoDataPanel()
        l.addWidget(self.info_panel)
        l.addWidget(self.motor_panel)

        self.protocol = Protocol()
        self.protocol.process_msg = self.process_msg
        self.msg_cntr = 0

        # Construct port:
        self.port = QSerialPort(self)
        self.port.readyRead.connect(self.do_read_bytes)
        self.logger.debug('Created class')

        # open port:
        self.do_open()
        self.do_go()
Exemple #15
0
    def __init__(self, context, parent=None):
        super().__init__(parent)

        self.win = parent
        self.ctx = context

        self.cmbPort = self.win.findChild(QObject, 'cmbPort')
        self.cmbBaud = self.win.findChild(QObject, 'cmbBaud')
        self.cmbData = self.win.findChild(QObject, 'cmbData')
        self.cmbChek = self.win.findChild(QObject, 'cmbParity')
        self.cmbStop = self.win.findChild(QObject, 'cmbStop')

        self.txtMain = self.win.findChild(QObject, 'txtMain')
        self.txtSend = self.win.findChild(QObject, 'txtSend')

        self.btnOpen = self.win.findChild(QObject, 'btnOpen')
        self.btnSend = self.win.findChild(QObject, 'btnSend')

        self.chkHexShow = self.win.findChild(QObject, 'chkHexShow')
        self.chkWavShow = self.win.findChild(QObject, 'chkWavShow')
        self.chkHexSend = self.win.findChild(QObject, 'chkHexSend')
        self.chkTimSend = self.win.findChild(QObject, 'chkTimSend')
        self.chkExtTran = self.win.findChild(QObject, 'chkExtTran')

        self.initSetting()

        self.ser = QSerialPort(self)
        self.ser.readyRead.connect(self.on_ser_dataAvailable)
Exemple #16
0
 def __init__(self, port, theme='day', parent=None):
     super().__init__(parent)
     self.setFont(Font().load())
     self.setAcceptRichText(False)
     self.setReadOnly(False)
     self.setUndoRedoEnabled(False)
     self.setContextMenuPolicy(Qt.CustomContextMenu)
     self.customContextMenuRequested.connect(self.context_menu)
     self.setObjectName('replpane')
     # open the serial port
     self.serial = QSerialPort(self)
     self.serial.setPortName(port)
     if self.serial.open(QIODevice.ReadWrite):
         self.serial.dataTerminalReady = True
         if not self.serial.isDataTerminalReady():
             # Using pyserial as a 'hack' to open the port and set DTR
             # as QtSerial does not seem to work on some Windows :(
             # See issues #281 and #302 for details.
             self.serial.close()
             pyser = serial.Serial(port)  # open serial port w/pyserial
             pyser.dtr = True
             pyser.close()
             self.serial.open(QIODevice.ReadWrite)
         self.serial.setBaudRate(115200)
         self.serial.readyRead.connect(self.on_serial_read)
         # clear the text
         self.clear()
         # Send a Control-C
         self.serial.write(b'\x03')
     else:
         raise IOError("Cannot connect to device on port {}".format(port))
     self.set_theme(theme)
Exemple #17
0
 def __init__(self, port, baudrate=115200):
     super().__init__()
     self.serial = QSerialPort()
     self._port = port
     self._baudrate = baudrate
     self.serial.setPortName(port)
     self.serial.setBaudRate(baudrate)
Exemple #18
0
 def begin(self):
     """SLOT: begin
             
     Launches the serial read/write signal loop
             
     Expects:
         none
             
     Connects to:
         QThread.started
     """
     path = glob.glob("/dev/tty.usbserial-*")
     self.serialPort = None
     try:
         path = path[0]
     except IndexError:
         self.displayRXMessage.emit("No serial connected")
         self.ready.emit()
     else:
         self.serialPort = QSerialPort(path)
         self.serialPort.setBaudRate(9600)
         self.buffer = bytearray()
         self.serialPort.readyRead.connect(self.readData)
         self.close.connect(self.serialPort.close)
         self.serialPort.open(QIODevice.ReadWrite)
     finally:
         self.lock = QMutex()
         self.broadcast.connect(self.writeData)
Exemple #19
0
 def __init__(self, baudRate, parent=None):
     super(self.__class__, self).__init__(parent)
     self.pollingTimer = QTimer()
     self.pollingTimer.timeout.connect(self.poll)
     self.ser = QSerialPort()
     self.ser.setBaudRate(baudRate)
     self.hasLogFile = False
     self.logFileName = ''
Exemple #20
0
    def get_ip(self):
        self.port = QSerialPort(self.cbxPort.currentData())
        self.port.setBaudRate(115200)

        DeviceIP(self.port).exec_()

        if self.port.isOpen():
            self.port.close()
    def __init__(self):
        super(MainUi, self).__init__()
        uic.loadUi(res_path('MainWindow.ui'), self)
        self.serial = QSerialPort(self)
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.updateTimer)

        self.setup()
        self.lastSerial = None
Exemple #22
0
    def __init__(self, *args, **kwargs):
        super(QtCore.QObject, self).__init__(*args, **kwargs)

        self.serial = QSerialPort()
        port = "COM14"
        self.serial.setPortName(port)
        if self.serial.open(QtCore.QIODevice.ReadWrite):
            self.serial.setDataTerminalReady(True)
            self.serial.setBaudRate(4800)
            self.serial.readyRead.connect(self.on_serial_read)
Exemple #23
0
	def portOpen(self):
		self.serial = QSerialPort()
		self.serial.setPortName(self.portNameBox.currentText())
		self.serial.open(QIODevice.ReadWrite)
		self.serial.setBaudRate(int(self.baudRateBox.currentText()))
		self.serial.setDataBits(QSerialPort.Data8)
		self.serial.setParity(QSerialPort.NoParity)
		self.serial.setFlowControl(QSerialPort.NoFlowControl)
		self.serial.setStopBits(QSerialPort.OneStop)
		self.portGroupBox.setEnabled(False)
Exemple #24
0
    def __init__(self):
        super(SerialWidget, self).__init__()
        self.com = QSerialPort()
        self.sendCnt = 0
        self.recvCnt = 0
        self.serialStatus = False

        self.initUI()
        self.detectSerialStatus()
        self.signalSlot()
 def __init__(self):
     super(RPMPlotter, self).__init__()
     # Setupui
     self.setupUi(self)
     # Create a serial port
     self.__serialPort = QSerialPort()
     # Setup Serialport
     # We are using USB serial driver, so the baud rate doesn't matter
     self.__serialPort.setBaudRate(QSerialPort.Baud115200,
                                   QSerialPort.Input)
     # Get the list of all available serial ports
     portsList = QSerialPortInfo.availablePorts()
     # Only connect to Chibios port
     chibiOsPort = None
     self.setWindowTitle("Experiment Data Collector")
     for port in portsList:
         if ("ChibiOS" in port.description()):
             chibiOsPort = port
             print(chibiOsPort.description())
     # Check of the device is connected.
     if (chibiOsPort is None):
         # We didn't find anything
         statusString = "Cannot find Chibios based device."
         print(statusString)
     else:
         # Set the serial port
         self.__serialPort.setPort(chibiOsPort)
         self.__serialPort.setDataBits(QSerialPort.Data8)
         self.__serialPort.setFlowControl(QSerialPort.NoFlowControl)
         self.__serialPort.setParity(QSerialPort.NoParity)
         self.__serialPort.setStopBits(QSerialPort.OneStop)
         # Connect signals and slots
         self.__serialPort.readyRead.connect(self.__onSerialPortReadyRead)
         self.startButton.clicked.connect(self.onStartButtonClicked)
         self.lineEdit.returnPressed.connect(self.onReferenceValueChanged)
         # Open the device
         self.__serialPort.open(QIODevice.ReadWrite)
         # Initialize variables
         # We track the reference and draw it as a line.
         self.__referenceArray = []
         # Timestamp in seconds
         self.__timeStampArray = []
         # RPM value
         self.__rpmArray = []
         # Voltage provided to the motor
         self.__voltageValue = []
         ## Curves
         self.__rpmCurve = pg.PlotCurveItem()
         self.__rpmCurve.setPen(pg.mkPen(color=(3, 39, 28), width=1.2))
         self.__referenceCurve = pg.PlotCurveItem()
         self.__referenceCurve.setPen(
             pg.mkPen(color=(214, 118, 17), width=1.2,
                      style=Qt.DashDotLine))
         self.graphicsView.addItem(self.__rpmCurve)
         self.graphicsView.addItem(self.__referenceCurve)
Exemple #26
0
    def run(self):

        serial = QSerialPort()
        serial.setPortName(self.portName)

        if not serial.open(QIODevice.ReadOnly):
            self.logger.error("can't open serial port")
            return

        while not self.quit:
            if serial.waitForReadyRead(self.waitTimeout):
                bytes = serial.readAll()

                while serial.waitForReadyRead(10):
                    bytes += serial.readAll()

                tag = self.decode_gwiot(bytes)
                now = calendar.timegm(time.gmtime())

                self.logger.debug("tag=%d, now=%d" % (tag, now))

                if tag > 0:
                    self.tagScan.emit(tag, self.hash_tag(tag), now,
                                      self.dump_pkt(bytes))
                else:
                    self.tagScanError.emit(tag, now, self.dump_pkt(bytes))
Exemple #27
0
 def initSerial(self, str_com):
     self.data_zigbee_list = []
     # 初始化串口
     self.ser_data = QSerialPort(STR_COM,
                                 baudRate=QSerialPort.Baud115200,
                                 readyRead=self.receive)
     self.ser_data.open(QIODevice.ReadWrite)
     if self.ser_data.isOpen():
         print('串口开启成功!')
     else:
         print('串口打开失败……')
Exemple #28
0
    def __init__(self):
        super().__init__()
        self.com = QSerialPort()

        self.Layout()
        self.CreateSignalSolt()
        self.RefreshCom()

        self.encoding = 'utf-8'
        self.recvCount = 0
        self.sendCount = 0
Exemple #29
0
 def __init__(self, parent=None):
     super(Serial, self).__init__(parent)
     self.setupUi(self)
     self.setWindowTitle("串口助手<V1.0> by-FXC")  # 设置标题
     self._num_send = 0  # 发送数据量
     self._num_receive = 0  # 接收数据量
     self._serial = QSerialPort(self)  # 用于连接串口的对象
     self._single_slot()  # 连接信号与槽
     self.get_available_ports()  # 获取可用的串口列表
     self.set_statusbar()  # 设置状态栏
     self.plainTextEdit_send.setPlainText("hello world!")
Exemple #30
0
    def __init__(self, *args, **kwargs):
        super(QtCore.QObject, self).__init__(*args, **kwargs)

        self.serial = QSerialPort()
        port = "/dev/ttyUSB0"
        self.serial.setPortName(port)
        if self.serial.open(QtCore.QIODevice.ReadWrite):
            self.serial.setDataTerminalReady(True)
            self.serial.setBaudRate(115200)
            self.serial.readyRead.connect(self.on_serial_read)
        else:
            print("Failed to open serial port")
Exemple #31
0
    def __init__(self):
        super().__init__()
        self.logger = logging.getLogger('controlpanel')
        l = QVBoxLayout(self)
        b = QPushButton("Gas")
        b.clicked.connect(self.do_go)
        l.addWidget(b)

        b2 = QPushButton("Bremsen")
        b2.clicked.connect(self.do_stop)
        l.addWidget(b2)

        self.motor_panel = MotorDataPanel()
        self.info_panel = InfoDataPanel()
        l.addWidget(self.info_panel)
        l.addWidget(self.motor_panel)

        self.protocol = Protocol()
        self.protocol.process_msg = self.process_msg
        self.msg_cntr = 0

        # Construct port:
        self.port = QSerialPort(self)
        self.port.readyRead.connect(self.do_read_bytes)
        self.logger.debug('Created class')

        # open port:
        self.do_open()
        self.do_go()
Exemple #32
0
    def __init__(self, port, parent=None):
        super().__init__(parent)
        self.setAcceptRichText(False)
        self.setReadOnly(False)
        self.setLineWrapMode(QTextEdit.NoWrap)
        self.setObjectName('replpane')

        # open the serial port
        self.serial = QSerialPort(self)
        self.serial.setPortName(port)
        self.serial.setBaudRate(115200)
        print(self.serial.open(QIODevice.ReadWrite))
        self.serial.readyRead.connect(self.on_serial_read)

        # clear the text
        self.clear()
Exemple #33
0
 def __init__(self, port, parent=None):
     super().__init__(parent)
     self.setAcceptRichText(False)
     self.setReadOnly(False)
     self.setLineWrapMode(QTextEdit.NoWrap)
     self.setObjectName('replpane')
     # open the serial port
     self.serial = QSerialPort(self)
     self.serial.setPortName(port)
     self.serial.setBaudRate(115200)
     if self.serial.open(QIODevice.ReadWrite):
         self.serial.readyRead.connect(self.on_serial_read)
         # clear the text
         self.clear()
         # Send a Control-C
         self.serial.write(b'\x03')
     else:
         raise IOError("Cannot connect to device on port {}".format(port))
Exemple #34
0
    def __init__(self, port, parent=None):
        super().__init__(parent)
        self.setAcceptRichText(False)
        self.setReadOnly(False)
        self.setLineWrapMode(QTextEdit.NoWrap)
        self.setObjectName("replpane")
        # A flag to indicate that we've sent some sort of escape
        # character e.g. \b
        self.escape_flag = False

        # open the serial port
        self.serial = QSerialPort(self)
        self.serial.setPortName(port)
        self.serial.setBaudRate(115200)
        print(self.serial.open(QIODevice.ReadWrite))
        self.serial.readyRead.connect(self.on_serial_read)

        # clear the text
        self.clear()
    def __init__(self, parent = None):
        super(SerialSimulate, self).__init__(parent)
        self.setObjectName('SerialSimulate')
        #
        self._currIndex = 0
        self._currFrameId = 0
        self._frameSize = 0
        self._streamBuff = []
        self._newBuff = [0] * 4096
        self._pkgBuff = [0] * 100
        self._serialSend = SerialSend()
        self._serialRecv = SerialRecv()

        self._serialConfig = SerialPortConfig()
        self._serialPort = QSerialPort(self)

        #
        self._serialPort.error.connect(self.onSerialPortError)
        self._serialPort.readyRead.connect(self.readData)

        #
        self._serialPort.setPortName('COM5')
        if self._serialPort.open(QIODevice.ReadWrite):
            self._serialPort.setBaudRate(QSerialPort.Baud115200)
            self._serialPort.setDataBits(QSerialPort.Data8)
            self._serialPort.setParity(QSerialPort.OddParity)
            self._serialPort.setStopBits(QSerialPort.OneStop)
            self.stateChanged.emit('Open')

        #
        self._serialRecv.lMBrakeP = SerialPortProxy.swapUint16(0)
        self._serialRecv.rMBrakeP = SerialPortProxy.swapUint16(0)
        self._serialRecv.lABrakeP = SerialPortProxy.swapUint16(5)
        self._serialRecv.rABrakeP = SerialPortProxy.swapUint16(5)
        self._serialRecv.lMRotateP = SerialPortProxy.swapUint16(0)
        self._serialRecv.rMRotateP = SerialPortProxy.swapUint16(0)
        self._serialRecv.lARotateP = SerialPortProxy.swapUint16(5)
        self._serialRecv.rARotateP = SerialPortProxy.swapUint16(5)
        self._serialRecv.lWheelSpd = self.convertToASCII(100)
        self._serialRecv.rWheelSpd = self.convertToASCII(100)

        #
        self._timerId = self.startTimer(100, Qt.PreciseTimer)
    def connect(self):
        if self._serial is None:
            self._serial = QSerialPort()
            self._serial.readyRead.connect(self.serial_read_bytes)

        self._serial.setPortName(self.serial_port)
        self._serial.setBaudRate(self.serial_baudrate)

        try:
            # attempt to connect
            self._log('Connecting serial port {:s} ...'.format(self.serial_port))
            self._serial.open(QIODevice.ReadWrite)
            
            # emit succesful connection signals
            self.serial_is_connected = True
            self.serial_connected.emit()
            
            self._log('Connected serial port!')
            
        except Exception as e:
            self._log_exception('Unable to open serial port', e)
Exemple #37
0
 def __init__(self, port, theme='day', parent=None):
     super().__init__(parent)
     self.setFont(Font().load())
     self.setAcceptRichText(False)
     self.setReadOnly(False)
     self.setUndoRedoEnabled(False)
     self.setContextMenuPolicy(Qt.CustomContextMenu)
     self.customContextMenuRequested.connect(self.context_menu)
     self.setObjectName('replpane')
     # open the serial port
     self.serial = QSerialPort(self)
     self.serial.setPortName(port)
     if self.serial.open(QIODevice.ReadWrite):
         self.serial.setBaudRate(115200)
         self.serial.readyRead.connect(self.on_serial_read)
         # clear the text
         self.clear()
         # Send a Control-C
         self.serial.write(b'\x03')
     else:
         raise IOError("Cannot connect to device on port {}".format(port))
     self.set_theme(theme)
Exemple #38
0
 def open_serial_link(self, port):
     """
     Creates a new serial link instance.
     """
     self.input_buffer = []
     self.serial = QSerialPort()
     self.serial.setPortName(port)
     if self.serial.open(QIODevice.ReadWrite):
         self.serial.dataTerminalReady = True
         if not self.serial.isDataTerminalReady():
             # Using pyserial as a 'hack' to open the port and set DTR
             # as QtSerial does not seem to work on some Windows :(
             # See issues #281 and #302 for details.
             self.serial.close()
             pyser = serial.Serial(port)  # open serial port w/pyserial
             pyser.dtr = True
             pyser.close()
             self.serial.open(QIODevice.ReadWrite)
         self.serial.setBaudRate(115200)
         self.serial.readyRead.connect(self.on_serial_read)
     else:
         raise IOError("Cannot connect to device on port {}".format(port))
Exemple #39
0
class REPLPane(QTextEdit):
    """
    REPL = Read, Evaluate, Print, Loop.

    This widget represents a REPL client connected to a BBC micro:bit running
    MicroPython.

    The device MUST be flashed with MicroPython for this to work.
    """

    def __init__(self, port, theme='day', parent=None):
        super().__init__(parent)
        self.setFont(Font().load())
        self.setAcceptRichText(False)
        self.setReadOnly(False)
        self.setObjectName('replpane')
        # open the serial port
        self.serial = QSerialPort(self)
        self.serial.setPortName(port)
        if self.serial.open(QIODevice.ReadWrite):
            self.serial.setBaudRate(115200)
            self.serial.readyRead.connect(self.on_serial_read)
            # clear the text
            self.clear()
            # Send a Control-C
            self.serial.write(b'\x03')
        else:
            raise IOError("Cannot connect to device on port {}".format(port))
        self.set_theme(theme)

    def set_theme(self, theme):
        """
        Sets the theme / look for the REPL pane.
        """
        if theme == 'day':
            self.setStyleSheet(DAY_STYLE)
        else:
            self.setStyleSheet(NIGHT_STYLE)

    def on_serial_read(self):
        """
        Called when the application gets data from the connected device.
        """
        self.process_bytes(bytes(self.serial.readAll()))

    def keyPressEvent(self, data):
        """
        Called when the user types something in the REPL.

        Correctly encodes it and sends it to the connected device.
        """
        key = data.key()
        msg = bytes(data.text(), 'utf8')

        if key == Qt.Key_Backspace:
            msg = b'\b'
        elif key == Qt.Key_Up:
            msg = b'\x1B[A'
        elif key == Qt.Key_Down:
            msg = b'\x1B[B'
        elif key == Qt.Key_Right:
            msg = b'\x1B[C'
        elif key == Qt.Key_Left:
            msg = b'\x1B[D'
        elif platform.system() == 'Darwin' and data.modifiers() == Qt.MetaModifier:
            # Handle the Control key. On OSX/macOS/Darwin (python calls this platform Darwin), this
            # is handled by Qt.MetaModifier. Other platforms (Linux, Windows) call this Qt.ControlModifier.
            # Go figure. See see http://doc.qt.io/qt-5/qt.html#KeyboardModifier-enum
            if Qt.Key_A <= key <= Qt.Key_Z:
                # The microbit treats an input of \x01 as Ctrl+A, etc.
                msg = bytes([1 + key - Qt.Key_A])
        self.serial.write(msg)

    def process_bytes(self, bs):
        """
        Given some incoming bytes of data, work out how to handle / display
        them in the REPL widget.
        """
        tc = self.textCursor()
        # The text cursor must be on the last line of the document. If it isn't
        # then move it there.
        while tc.movePosition(QTextCursor.Down):
            pass
        for b in bs:
            if b == 8:  # \b
                tc.movePosition(QTextCursor.Left)
                self.setTextCursor(tc)
            elif b == 13:  # \r
                pass
            else:
                tc.deleteChar()
                self.setTextCursor(tc)
                self.insertPlainText(chr(b))
        self.ensureCursorVisible()

    def clear(self):
        """
        Clears the text of the REPL.
        """
        self.setText('')
class SerialPortProxy(QObject):
    """
    class SerialPortProxy
    """

    stateChanged = QtCore.pyqtSignal(str)
    serialPortError = QtCore.pyqtSignal(QSerialPort.SerialPortError, str)
    displayRespond = QtCore.pyqtSignal(SerialRecv, QDateTime)

    def __init__(self, parent=None):
        super(SerialPortProxy, self).__init__(parent)
        self.setObjectName("SerialPortProxy")

        #
        self._currIndex = 0
        self._currFrameId = 0
        self._frameSize = 0
        self._streamBuff = []
        self._newBuff = [0] * 4096
        self._pkgBuff = [0] * 100
        self._serialRecv = SerialRecv()

        self._serialConfig = SerialPortConfig()
        self._serialPort = QSerialPort(self)

        #
        self._serialPort.error.connect(self.onSerialPortError)
        self._serialPort.readyRead.connect(self.readData)

        #
        self._serialSimulate = None  # SerialSimulate(self)

        # read configuration
        settings = QSettings(self)
        # group - serialport properties
        settings.beginGroup("Settings/" + self.objectName() + "/SerialPort")
        self._serialConfig.port = settings.value("port", "COM1")
        infolist = settings.value("info", "115200-8-N-1").split("-")
        self._serialConfig.baudRate = int(infolist[0])
        dataBits = int(infolist[1])
        self._serialConfig.dataBits = (
            QSerialPort.Data5
            if dataBits == 5
            else QSerialPort.Data6
            if dataBits == 6
            else QSerialPort.Data7
            if dataBits == 7
            else QSerialPort.Data8
            if dataBits == 8
            else QSerialPort.Data8
        )
        parity = infolist[2][0].upper()
        self._serialConfig.parity = (
            QSerialPort.NoParity
            if parity == "N"
            else QSerialPort.EvenParity
            if parity == "E"
            else QSerialPort.OddParity
            if parity == "O"
            else QSerialPort.SpaceParity
            if parity == "S"
            else QSerialPort.MarkParity
            if parity == "M"
            else QSerialPort.NoParity
        )
        stopBits = int(float(infolist[3]) * 10)
        self._serialConfig.stopBits = (
            QSerialPort.OneStop
            if stopBits == 10
            else QSerialPort.OneAndHalfStop
            if stopBits == 15
            else QSerialPort.TwoStop
            if stopBits == 20
            else QSerialPort.OneStop
        )
        settings.endGroup()

    def config(self):
        return self._serialConfig

    def setConfig(self, info):
        self._serialConfig.port = info.port
        self._serialConfig.baudRate = info.baudRate
        self._serialConfig.dataBits = info.dataBits
        self._serialConfig.parity = info.parity
        self._serialConfig.stopBits = info.stopBits

        #
        settings = QSettings(self)
        settings.beginGroup("Settings/" + self.objectName() + "/SerialPort")
        settings.setValue("port", self._serialConfig.port)
        settings.setValue("info", self.__str__())
        settings.endGroup()

    @QtCore.pyqtSlot(QSerialPort.SerialPortError, str)
    def onSerialPortError(self, error):
        print("SerialPort open failed!, %d" % error)
        self.serialPortError.emit(
            error,
            "No error"
            if error == QSerialPort.NoError
            else "Device not found"
            if error == QSerialPort.DeviceNotFoundError
            else "Permission error"
            if error == QSerialPort.PermissionError
            else "Open error"
            if error == QSerialPort.OpenError
            else "Parity error"
            if error == QSerialPort.ParityError
            else "Framing error"
            if error == QSerialPort.FramingError
            else "Break Condition error"
            if error == QSerialPort.BreakConditionError
            else "Write error"
            if error == QSerialPort.WriteError
            else "Read error"
            if error == QSerialPort.ReadError
            else "Resource error"
            if error == QSerialPort.ResourceError
            else "Unsupported operation"
            if error == QSerialPort.UnsupportedOperationError
            else "Unknown error"
            if error == QSerialPort.UnknownError
            else "Timeout"
            if error == QSerialPort.TimeoutError
            else "Not open"
            if error == QSerialPort.NotOpenError
            else "%d" % error,
        )

    @QtCore.pyqtSlot()
    def start(self):
        if self._serialPort.isOpen():
            self._serialPort.close()

        # config serialport properties
        self._serialPort.setPortName(self._serialConfig.port)
        if self._serialPort.open(QIODevice.ReadWrite):
            self._serialPort.setBaudRate(self._serialConfig.baudRate)
            self._serialPort.setDataBits(self._serialConfig.dataBits)
            self._serialPort.setParity(self._serialConfig.parity)
            self._serialPort.setStopBits(self._serialConfig.stopBits)
            self.stateChanged.emit("Open")

    @QtCore.pyqtSlot()
    def stop(self):
        if self._serialPort.isOpen():
            self._serialPort.close()
            self.stateChanged.emit("Close")

    @QtCore.pyqtSlot()
    def save(self):
        self.setProperty("portState", self._serialPort.isOpen())
        self.stop()
        # save state of simulator
        if self._serialSimulate:
            self._serialSimulate.save()

    @QtCore.pyqtSlot()
    def restore(self):
        self.start() if bool(self.property("portState")) else self.stop()

        # restore state of simulator
        if self._serialSimulate:
            self._serialSimulate.restore()

    @QtCore.pyqtSlot(SerialSend)
    def writeData(self, data):
        if not self._serialPort.isOpen():
            # warning...
            return 0
        return int(self._serialPort.write(data.pack()))

    @QtCore.pyqtSlot()
    def readData(self):
        self._streamBuff = self._serialPort.read(4096)
        self.unpack()
        return self._streamBuff.__len__()

    def unpack(self):
        for (i, value) in enumerate(self._streamBuff):
            if self._currIndex < self._serialRecv._offset_length:  # 1.frame-header
                self._frameSize = 0
                if value == self._serialRecv._headers[self._currIndex]:
                    self._newBuff[self._currIndex] = value
                    self._currIndex += 1
                else:
                    self._currIndex = 0
                continue
            elif self._currIndex == self._serialRecv._offset_length:  # 2.frame-length
                if value == self._serialRecv.length:
                    pass
                else:
                    self._currIndex = 0
                    continue
                self._frameSize = value
                self._newBuff[i] = value
                self._currIndex += 1
                continue
            elif self._currIndex == self._serialRecv._offset_index:  # 3.frame-index
                self._currFrameId = value
                self._newBuff[i] = value
                self._currIndex += 1
                continue
            elif self._currIndex < self._frameSize:  # 4.frame-data
                self._newBuff[i] = value
                self._currIndex += 1
            if self._currIndex == self._frameSize:  # receive a full frame successfully
                # 5.frame-sum
                s = 0
                for index in range(0, self._serialRecv._offset_sum):
                    s = (s + self._newBuff[index]) & 0xFF
                if self._newBuff[self._serialRecv._offset_sum] != s:
                    self._currIndex = 0
                    # continue  # invalid frame
                # 6.frame-tail
                if self._newBuff[self._serialRecv._offset_tail] != int(self._serialRecv.tail):
                    self._currIndex = 0  # invalid frame
                    continue
                # 7.save as...
                self._pkgBuff = self._newBuff[0 : self._frameSize]
                # 8.dispatch
                self.dispatch()
                # 9.reset
                self._currIndex = 0

    def dispatch(self):
        # save as...
        self._serialRecv.unpack(bytes(self._pkgBuff))

        # convert

        self._serialRecv.lMBrakeP = self.swapUint16(self._serialRecv.lMBrakeP)
        self._serialRecv.lABrakeP = self.swapUint16(self._serialRecv.lABrakeP)
        self._serialRecv.rMBrakeP = self.swapUint16(self._serialRecv.rMBrakeP)
        self._serialRecv.rABrakeP = self.swapUint16(self._serialRecv.rABrakeP)

        self._serialRecv.lMRotateP = self.swapUint16(self._serialRecv.lMRotateP)
        self._serialRecv.lARotateP = self.swapUint16(self._serialRecv.lARotateP)
        self._serialRecv.rMRotateP = self.swapUint16(self._serialRecv.rMRotateP)
        self._serialRecv.rARotateP = self.swapUint16(self._serialRecv.rARotateP)

        self._serialRecv.lWheelSpd = self.swapUint32(self._serialRecv.lWheelSpd)
        self._serialRecv.rWheelSpd = self.swapUint32(self._serialRecv.rWheelSpd)

        # emit
        self.displayRespond.emit(self._serialRecv, QDateTime.currentDateTime())

    _crc16_table = bytes(256)

    @staticmethod
    def calcRCR16(data):
        cnta = 0
        cntb = 0
        crcval = 0

    @staticmethod
    def serialPortSendSum(data):
        return 0  # TODO
        s = 0
        for i in range(0, data._offset_sum):
            s = (s + data[i]) & 0xFF
        return s

    @staticmethod
    def serialPortRecvSum(data):
        return 0  # TODO
        s = 0
        for i in range(0, data._offset_sum):
            s = (s + data[i]) & 0xFF
        return s

    @staticmethod
    def swapUint16(value):
        return value

    @staticmethod
    def swapUint32(value):
        return value

    @staticmethod
    def convertFromASCII(value):
        return value

    @staticmethod
    def convertToASCII(value):
        return value
Exemple #41
0
class REPLPane(QTextEdit):
    """
    REPL = Read, Evaluate, Print, Loop.

    This widget represents a REPL client connected to a BBC micro:bit running
    MicroPython.

    The device MUST be flashed with MicroPython for this to work.
    """

    def __init__(self, port, theme='day', parent=None):
        super().__init__(parent)
        self.setFont(Font().load())
        self.setAcceptRichText(False)
        self.setReadOnly(False)
        self.setUndoRedoEnabled(False)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.context_menu)
        self.setObjectName('replpane')
        # open the serial port
        self.serial = QSerialPort(self)
        self.serial.setPortName(port)
        if self.serial.open(QIODevice.ReadWrite):
            self.serial.setBaudRate(115200)
            self.serial.readyRead.connect(self.on_serial_read)
            # clear the text
            self.clear()
            # Send a Control-C
            self.serial.write(b'\x03')
        else:
            raise IOError("Cannot connect to device on port {}".format(port))
        self.set_theme(theme)

    def paste(self):
        """
        Grabs clipboard contents then sends down the serial port.
        """
        clipboard = QApplication.clipboard()
        if clipboard and clipboard.text():
            self.serial.write(bytes(clipboard.text(), 'utf8'))

    def context_menu(self):
        """"
        Creates custom context menu with just copy and paste.
        """
        menu = QMenu(self)
        if platform.system() == 'Darwin':
            copy_keys = QKeySequence(Qt.CTRL + Qt.Key_C)
            paste_keys = QKeySequence(Qt.CTRL + Qt.Key_V)
        else:
            copy_keys = QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_C)
            paste_keys = QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_V)

        menu.addAction("Copy", self.copy, copy_keys)
        menu.addAction("Paste", self.paste, paste_keys)
        menu.exec_(QCursor.pos())

    def cursor_to_end(self):
        """
        Moves the cursor to the very end of the available text.
        """
        tc = self.textCursor()
        tc.movePosition(QTextCursor.End)
        self.setTextCursor(tc)

    def set_theme(self, theme):
        """
        Sets the theme / look for the REPL pane.
        """
        if theme == 'day':
            self.setStyleSheet(DAY_STYLE)
        else:
            self.setStyleSheet(NIGHT_STYLE)

    def on_serial_read(self):
        """
        Called when the application gets data from the connected device.
        """
        self.process_bytes(bytes(self.serial.readAll()))

    def keyPressEvent(self, data):
        """
        Called when the user types something in the REPL.

        Correctly encodes it and sends it to the connected device.
        """
        key = data.key()
        msg = bytes(data.text(), 'utf8')
        if key == Qt.Key_Backspace:
            msg = b'\b'
        elif key == Qt.Key_Up:
            msg = b'\x1B[A'
        elif key == Qt.Key_Down:
            msg = b'\x1B[B'
        elif key == Qt.Key_Right:
            msg = b'\x1B[C'
        elif key == Qt.Key_Left:
            msg = b'\x1B[D'
        elif key == Qt.Key_Home:
            msg = b'\x1B[H'
        elif key == Qt.Key_End:
            msg = b'\x1B[F'
        elif (platform.system() == 'Darwin' and
                data.modifiers() == Qt.MetaModifier) or \
             (platform.system() != 'Darwin' and
                data.modifiers() == Qt.ControlModifier):
            # Handle the Control key. On OSX/macOS/Darwin (python calls this
            # platform Darwin), this is handled by Qt.MetaModifier. Other
            # platforms (Linux, Windows) call this Qt.ControlModifier. Go
            # figure. See http://doc.qt.io/qt-5/qt.html#KeyboardModifier-enum
            if Qt.Key_A <= key <= Qt.Key_Z:
                # The microbit treats an input of \x01 as Ctrl+A, etc.
                msg = bytes([1 + key - Qt.Key_A])
        elif (data.modifiers() == Qt.ControlModifier | Qt.ShiftModifier) or \
                (platform.system() == 'Darwin' and
                    data.modifiers() == Qt.ControlModifier):
            # Command-key on Mac, Ctrl-Shift on Win/Lin
            if key == Qt.Key_C:
                self.copy()
                msg = b''
            elif key == Qt.Key_V:
                self.paste()
                msg = b''
        self.serial.write(msg)

    def process_bytes(self, data):
        """
        Given some incoming bytes of data, work out how to handle / display
        them in the REPL widget.
        """
        tc = self.textCursor()
        # The text cursor must be on the last line of the document. If it isn't
        # then move it there.
        while tc.movePosition(QTextCursor.Down):
            pass
        i = 0
        while i < len(data):
            if data[i] == 8:  # \b
                tc.movePosition(QTextCursor.Left)
                self.setTextCursor(tc)
            elif data[i] == 13:  # \r
                pass
            elif data[i] == 27 and data[i + 1] == 91:  # VT100 cursor: <Esc>[
                i += 2  # move index to after the [
                m = re.search(r'(?P<count>[\d]*)(?P<action>[ABCDK])',
                              data[i:].decode('utf-8'))

                # move to (almost) after control seq (will ++ at end of loop)
                i += m.end() - 1

                if m.group("count") == '':
                    count = 1
                else:
                    count = int(m.group("count"))

                if m.group("action") == "A":  # up
                    tc.movePosition(QTextCursor.Up, n=count)
                    self.setTextCursor(tc)
                elif m.group("action") == "B":  # down
                    tc.movePosition(QTextCursor.Down, n=count)
                    self.setTextCursor(tc)
                elif m.group("action") == "C":  # right
                    tc.movePosition(QTextCursor.Right, n=count)
                    self.setTextCursor(tc)
                elif m.group("action") == "D":  # left
                    tc.movePosition(QTextCursor.Left, n=count)
                    self.setTextCursor(tc)
                elif m.group("action") == "K":  # delete things
                    if m.group("count") == "":  # delete to end of line
                        tc.movePosition(QTextCursor.EndOfLine,
                                        mode=QTextCursor.KeepAnchor)
                        tc.removeSelectedText()
                        self.setTextCursor(tc)
            elif data[i] == 10:  # \n
                tc.movePosition(QTextCursor.End)
                self.setTextCursor(tc)
                self.insertPlainText(chr(data[i]))
            else:
                tc.deleteChar()
                self.setTextCursor(tc)
                self.insertPlainText(chr(data[i]))
            i += 1
        self.ensureCursorVisible()

    def clear(self):
        """
        Clears the text of the REPL.
        """
        self.setText('')
Exemple #42
0
class REPLPane(QTextEdit):
    """
    REPL = Read, Evaluate, Print, Loop.

    This widget represents a REPL client connected to a BBC micro:bit.
    """
    def __init__(self, port, parent=None):
        super().__init__(parent)
        self.setAcceptRichText(False)
        self.setReadOnly(False)
        self.setLineWrapMode(QTextEdit.NoWrap)
        self.setObjectName('replpane')

        # open the serial port
        self.serial = QSerialPort(self)
        self.serial.setPortName(port)
        self.serial.setBaudRate(115200)
        print(self.serial.open(QIODevice.ReadWrite))
        self.serial.readyRead.connect(self.on_serial_read)
        self.serial_input_buffer = b''

        # clear the text
        self.clear()

    def on_serial_read(self):
        self.process_bytes(bytes(self.serial.readAll()))

    def keyPressEvent(self, data):
        text = data.text()
        msg = bytes(text, 'utf8')
        key = data.key()
        if key == Qt.Key_Backspace:
            msg = b'\b'
        elif key == Qt.Key_Up:
            msg = b'\x1B[A'
        elif key == Qt.Key_Down:
            msg = b'\x1B[B'
        elif key == Qt.Key_Right:
            msg = b'\x1B[C'
        elif key == Qt.Key_Left:
            msg = b'\x1B[D'
        self.serial.write(msg)

    def process_bytes(self, bs):
        bs = self.serial_input_buffer + bs
        while len(bs):
            num_use = 0
            if bs[0] == 8: # backspace
                self.delete()
                num_use = 1
            elif bs[0] == 13: # \r
                # ignore
                num_use = 1
            elif bs[0] == 27: # escape
                if bs.startswith(b'\x1b[K'):
                    # kill to end of line
                    num_use = 3
                elif bs.startswith(b'\x1b[') and len(bs) >= 3 and chr(bs[2]).isdigit():
                    n = bs[2] - ord('0')
                    cmd_idx = 3
                    if len(bs) >= 4 and chr(bs[3]).isdigit():
                        n = 10 * n + bs[3] - ord('0')
                        cmd_idx = 4
                    if cmd_idx < len(bs):
                        if bs[cmd_idx] == ord('D'):
                            # backspace n chars
                            for i in range(n):
                                self.delete()
                            num_use = cmd_idx + 1
                if num_use == 0:
                    # unknown or incomplete escape sequence
                    print(bs)
            else:
                self.append(chr(bs[0]))
                num_use = 1
            if num_use == 0:
                break
            bs = bs[num_use:]
        self.serial_input_buffer = bs

    def append(self, txt):
        tc = self.textCursor()
        tc.movePosition(QTextCursor.End)
        self.setTextCursor(tc)
        self.insertPlainText(txt)
        self.ensureCursorVisible()

    def delete(self):
        tc = self.textCursor()
        tc.deletePreviousChar()

    def clear(self):
        self.setText('')

    def kill(self):
        if self.serial.isOpen():
            self.serial.close()
Exemple #43
0
def open_serial_port(name):
    try:
        serial_port = QSerialPort()
        serial_port.setPortName(name)
        serial_port.setBaudRate(QSerialPort.Baud9600, QSerialPort.AllDirections)
        serial_port.setParity(QSerialPort.NoParity)
        serial_port.setStopBits(QSerialPort.OneStop)
        serial_port.setDataBits(QSerialPort.Data8)
        serial_port.setFlowControl(QSerialPort.NoFlowControl)
        serial_port.open(QSerialPort.ReadWrite)
        return serial_port
    except Exception as e:
        print("open_serial_port", e)
        return None
Exemple #44
0
class REPLPane(QTextEdit):
    """
    REPL = Read, Evaluate, Print, Loop.

    This widget represents a REPL client connected to a BBC micro:bit.
    """
    def __init__(self, port, parent=None):
        super().__init__(parent)
        self.setAcceptRichText(False)
        self.setReadOnly(False)
        self.setLineWrapMode(QTextEdit.NoWrap)
        self.setObjectName('replpane')

        # open the serial port
        self.serial = QSerialPort(self)
        self.serial.setPortName(port)
        self.serial.setBaudRate(115200)
        print(self.serial.open(QIODevice.ReadWrite))
        self.serial.readyRead.connect(self.on_serial_read)

        # clear the text
        self.clear()

    def on_serial_read(self):
        self.process_bytes(bytes(self.serial.readAll()))

    def keyPressEvent(self, data):
        key = data.key()
        msg = bytes(data.text(), 'utf8')

        if key == Qt.Key_Backspace:
            msg = b'\b'
        elif key == Qt.Key_Up:
            msg = b'\x1B[A'
        elif key == Qt.Key_Down:
            msg = b'\x1B[B'
        elif key == Qt.Key_Right:
            msg = b'\x1B[C'
        elif key == Qt.Key_Left:
            msg = b'\x1B[D'
        elif data.modifiers() == Qt.MetaModifier:
            # Handle the Control key.  I would've expected us to have to test
            # for Qt.ControlModifier, but on (my!) OSX Qt.MetaModifier does
            # correspond to the Control key.  I've read something that suggests
            # that it's different on other platforms.
            if Qt.Key_A <= key <= Qt.Key_Z:
                # The microbit treats an input of \x01 as Ctrl+A, etc.
                msg = bytes([1 + key - Qt.Key_A])
        self.serial.write(msg)

    def process_bytes(self, bs):
        tc = self.textCursor()

        for b in bs:
            if b == 8: # \b
                tc.movePosition(QTextCursor.Left)
                self.setTextCursor(tc)
            elif b == 13: # \r
                pass
            else:
                tc.deleteChar()
                self.setTextCursor(tc)
                self.insertPlainText(chr(b))

        self.ensureCursorVisible()

    def clear(self):
        self.setText('')
class KPSerialInterface(QtCore.QObject):

    subsys = 'SERIAL'
    msg_parser_period = 0.005

        
    # S I G N A L S 
    #===========================================================================
    connected = pyqtSignal()
    disconnected = pyqtSignal()
    finished = pyqtSignal()
    rc_command = pyqtSignal(KPRemoteControlState)

    
    # C O N S T R U C T O R 
    #===========================================================================
    def __init__(self, serial_port="COM4", serial_baudrate=250000, **kwds):
        super(KPSerialInterface, self).__init__(**kwds)
        
        # thread variables
        self.terminate = False
        self._current_time = time.time()
        self._previous_time = self._current_time
        
        # serial interface
        self._serial = None
        self.is_connected = False
        self.port = serial_port
        self.baudrate = serial_baudrate
        self._rx_buffer = collections.deque(maxlen=512)

        # initialize control timers
        self._message_parser_timer = QTimer()
        
        self._message_parser_timer.timeout.connect(self.parse_rx_buffer)
        self._message_parser_timer.start(KPSerialInterface.msg_parser_period * 1000.0)

        # data variables
        self._rc_cmd = KPRemoteControlState()
        

        
    # M E T H O D S 
    #===========================================================================
    def connect(self):
        if self._serial is None:
            self._serial = QSerialPort()
            self._serial.readyRead.connect(self.serial_read_bytes)

        self._serial.setPortName(self.serial_port)
        self._serial.setBaudRate(self.serial_baudrate)

        try:
            # attempt to connect
            self._log('Connecting serial port {:s} ...'.format(self.serial_port))
            self._serial.open(QIODevice.ReadWrite)
            
            # emit succesful connection signals
            self.serial_is_connected = True
            self.serial_connected.emit()
            
            self._log('Connected serial port!')
            
        except Exception as e:
            self._log_exception('Unable to open serial port', e)
    
    
    # P R I V A T E   M E T H O D S 
    #===========================================================================
    def _parse_message(self, message):
        msg_bytes = ''
        for b in message:
            msg_bytes += hex(b) + " "

        #print("Message received! {:s}".format(msg_bytes))

        message_type = message[0]

        if message_type == 0x40:
            button_state = message[1]
            message_bytes = bytearray(message)
            joystick_x = struct.unpack("H", message_bytes[2:4])[0]
            joystick_y = struct.unpack("H", message_bytes[4:6])[0]
            joystick_z = struct.unpack("H", message_bytes[6:8])[0]

            #print("State message: {:4s} {:4d} {:4d} {:4d}".format(hex(button_state), joystick_x, joystick_y, joystick_z))

            # construct remote control command object
            #rc_cmd = KPRemoteControlState(button_state, joystick_x, joystick_y, joystick_z)
            self._rc_cmd.set_button_states(button_state)
            self._rc_cmd.joystick['x'] = joystick_x
            self._rc_cmd.joystick['y'] = joystick_y
            self._rc_cmd.joystick['z'] = joystick_z

            self.rc_command.emit(self._rc_cmd)
        
    
    # S L O T S 
    #===========================================================================
    
    @pyqtSlot()
    def process(self):
        while not self.terminate:
            
            # service Qt events
            QCoreApplication.processEvents()
            
            
        # thread termination
        self.disconnect()
        self._log('Serial interface thread terminating...')
        self.finished.emit()


    @pyqtSlot()
    def connect(self):
        if self._serial is None:
            self._serial = QSerialPort()
            self._serial.readyRead.connect(self.read_data)

        self._serial.setPortName(self.port)
        self._serial.setBaudRate(self.baudrate)

        try:
            # attempt to connect
            self._log('Connecting serial port {:s} ...'.format(self.port))
            self._serial.open(QIODevice.ReadWrite)
            
            # emit succesful connection signals
            self.is_connected = True
            self.connected.emit()
            
            self._log('Connected serial port!')
            
        except Exception as e:
            self._log_exception('Unable to open serial port', e)


    @pyqtSlot()
    def read_data(self):
        rx_bytes = self._serial.readAll()

        #print("len = {:3d}".format(len(self._rx_buffer)))
        #print(rx_bytes.data())

        for b in rx_bytes.data():
             self._rx_buffer.append(b)

        '''
        try:
            print(self._rx_buffer)
        except Exception as e:
            self._log_exception('EXCEPTION! {:s}'.format(str(e)), e)
        '''

    @pyqtSlot()
    def parse_rx_buffer(self):
        msg_size = 0

        if len(self._rx_buffer) >= 1:
            byte1 = self._rx_buffer[0]

            if byte1 != ord('$'):
                self._rx_buffer.popleft()
                return

        if len(self._rx_buffer) >= 2:
            byte2 = self._rx_buffer[1]

            if byte2 != ord('$'):
                self._rx_buffer.popleft()
                self._rx_buffer.popleft()
                return

        if len(self._rx_buffer) >= 3:
            msg_size = self._rx_buffer[2]

        if len(self._rx_buffer) >= (3 + msg_size):

            # pop the header
            self._rx_buffer.popleft()
            self._rx_buffer.popleft()
            self._rx_buffer.popleft()

            # pop the message
            message = []
            for i in range(msg_size):
                message.append(self._rx_buffer.popleft())

            self._parse_message(message)





        
    @pyqtSlot()
    def disconnect(self):
        if self._serial is not None:
            #self._serial.readyRead.disconnect(self)
            self._serial.close()
            self._rx_buffer.clear()
            self.is_connected = False
            self.disconnected.emit()
            self._log('Disconnected serial port')
        
    # H E L P E R   F U N C T I O N S 
    #===========================================================================
    def _log(self, log_message, log_type='info', log_data=None):
        Logger.log(KPSerialInterface.subsys, log_message, log_type, log_data)
        
    def _log_warning(self, log_message, log_data=None):
        Logger.log_warning(KPSerialInterface.subsys, log_message, log_data)
        
    def _log_exception(self, log_message, log_exception):
        Logger.log_exception(KPSerialInterface.subsys, log_message, log_exception)
Exemple #46
0
class ControlPanel(QWidget):
    """ This control panel steers the dr robot protocol.
        It opens the serial port, and handles the protocol.
    """
    def __init__(self):
        super().__init__()
        self.logger = logging.getLogger('controlpanel')
        l = QVBoxLayout(self)
        b = QPushButton("Gas")
        b.clicked.connect(self.do_go)
        l.addWidget(b)

        b2 = QPushButton("Bremsen")
        b2.clicked.connect(self.do_stop)
        l.addWidget(b2)

        self.motor_panel = MotorDataPanel()
        self.info_panel = InfoDataPanel()
        l.addWidget(self.info_panel)
        l.addWidget(self.motor_panel)

        self.protocol = Protocol()
        self.protocol.process_msg = self.process_msg
        self.msg_cntr = 0

        # Construct port:
        self.port = QSerialPort(self)
        self.port.readyRead.connect(self.do_read_bytes)
        self.logger.debug('Created class')

        # open port:
        self.do_open()
        self.do_go()

    def closeEvent(self, event):
        self.port.close()
        super().closeEvent(event)

    def do_open(self):
        self.logger.debug('Opening port')
        self.port.setPortName('/dev/ttyUSB0')
            
        self.logger.debug('Port name {}'.format(self.port.portName()))
        self.logger.debug('Baud rate: {}'.format(self.port.baudRate()))
        self.logger.debug('Data bits: {}'.format(self.port.dataBits()))
        res = self.port.open(QIODevice.ReadWrite)
        if not res:
            self.logger.error('Error opening port {}'.format(self.port.error()))
        if not self.port.setBaudRate(115200):
            self.logger.error('Error setting baudrate: {}'.format(self.port.error()))
        self.logger.debug('Port opened')
        self.logger.debug('Port name {}'.format(self.port.portName()))
        self.logger.debug('Baud rate: {}'.format(self.port.baudRate()))

    def do_read_bytes(self):
        data = self.port.read(100)
        # self.logger.debug('Read {} bytes'.format(data))
        self.protocol.add_bytes(data)

    def process_msg(self, typ, data):
        """
            Dissect the contents of the message.
              #define COMTYPE_MOTOR           40
        """
        self.msg_cntr += 1
        self.info_panel.msgcnt = self.msg_cntr
        COMTYPE_SYSTEM = 0xFF
        COMTYPE_MOTOR_SENSOR = 0x7B
        COMTYPE_CUSTOM_SENSOR = 0x7C
        COMTYPE_STANDARD_SENSOR = 0x7D
        COMTYPE_SENSOR = 0x7F
        if typ == COMTYPE_MOTOR_SENSOR:
            # format: 6x angles, 6x current, pos, vel, pos, vel
            enc0, enc1, _, _, _, _, cur0, cur1, _, _, _, _, pos0, vel0, pos1, vel1, bitmask = struct.unpack('<HHH HHH HHH HHH H H H H B', data)
            self.motor_panel.pos0 = pos0
            self.motor_panel.pos1 = pos1
            self.motor_panel.enc0 = enc0
            self.motor_panel.enc1 = enc1
            self.motor_panel.vel0 = vel0
            self.motor_panel.vel1 = vel1
        elif typ == COMTYPE_SENSOR:
            #self.logger.warning('Sensor data')
            pass
        elif typ == COMTYPE_CUSTOM_SENSOR:
            #self.logger.warning('Custom sensor data')
            pass
        elif typ == COMTYPE_STANDARD_SENSOR:
            #self.logger.warning('Standard sensor data')
            pass
        else:
            self.logger.warning('Unknown packet type {}'.format(typ))

    def send_msg(self, typ, data):
        msg = self.protocol.make_msg(typ, data)
        print(msg)

    def set_motor_velctrl_pid(self, channel, kp, ki, kd):
        """
  const unsigned char POSITIONPID = 7;
  const unsigned char MOTORVELOCITYCTRL = 26;
  const unsigned char MOTORVELOCITYCTRLALL = 27;

  const unsigned char SERVOCTRL = 28;
  const unsigned char SERVOCTRLALL = 29;
  const unsigned char MOTORENABLE = 0x1e;

  const unsigned char MOTORFRICCOMP = 31;
  const unsigned char CUSTOMIO = 22;
  const unsigned char POWERCTRL = 22;

        """
        MOTORPARAMETERSETTING = 7
        VELOCITYPID = 8
        KP_ID = 1
        KD_ID = 2
        KI_ID = 3
        msg = struct.pack('<BB BH BH BH', VELOCITYPID, channel, KP_ID, kp, KD_ID, ki, KI_ID, ki)
        assert len(msg) == 11, str(msg)
        self.send_msg(MOTORPARAMETERSETTING, msg)
        
    def do_go(self):
        self.logger.debug('Connect!')
        self.set_motor_velctrl_pid(0, 1, 0, 1)

    def do_stop(self):
        self.logger.debug('Stop!')
Exemple #47
0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from PyQt5.QtCore import QCoreApplication
from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo
from middleware_common import *
from OldMiddleWare import parse_command
import sys
import time

if __name__ == "__main__":
    a = QCoreApplication(sys.argv)
    serial_port = QSerialPort()
    serial_port.setPortName(sys.argv[1])
    serial_port.setBaudRate(QSerialPort.Baud9600, QSerialPort.AllDirections)
    serial_port.setParity(QSerialPort.NoParity)
    serial_port.setStopBits(QSerialPort.OneStop)
    serial_port.setDataBits(QSerialPort.Data8)
    serial_port.setFlowControl(QSerialPort.NoFlowControl)
    serial_port.open(QSerialPort.ReadWrite)
    time.sleep(3)
    set_profile(serial_port, 1)
    # set_date_time(serial_port)
    set_wifi(serial_port)
    set_end_point(serial_port)
    time.sleep(3)
    while True:
        try:
            buffer = serial_port.read(100)
            if len(buffer) > 0:
                print(buffer, end='')
Exemple #48
0
class Window(QMainWindow):
    """
    Defines the look and characteristics of the application's main window.
    """

    title = _("Mu {}").format(__version__)
    icon = "icon"
    timer = None
    usb_checker = None
    serial = None
    repl = None
    plotter = None

    _zoom_in = pyqtSignal(int)
    _zoom_out = pyqtSignal(int)
    close_serial = pyqtSignal()
    write_to_serial = pyqtSignal(bytes)
    data_received = pyqtSignal(bytes)

    def zoom_in(self):
        """
        Handles zooming in.
        """
        self._zoom_in.emit(2)

    def zoom_out(self):
        """
        Handles zooming out.
        """
        self._zoom_out.emit(2)

    def connect_zoom(self, widget):
        """
        Connects a referenced widget to the zoom related signals.
        """
        self._zoom_in.connect(widget.zoomIn)
        self._zoom_out.connect(widget.zoomOut)

    @property
    def current_tab(self):
        """
        Returns the currently focussed tab.
        """
        return self.tabs.currentWidget()

    def set_read_only(self, is_readonly):
        """
        Set all tabs read-only.
        """
        self.read_only_tabs = is_readonly
        for tab in self.widgets:
            tab.setReadOnly(is_readonly)

    def get_load_path(self, folder):
        """
        Displays a dialog for selecting a file to load. Returns the selected
        path. Defaults to start in the referenced folder.
        """
        path, _ = QFileDialog.getOpenFileName(self.widget, 'Open file', folder,
                                              '*.py *.PY *.hex')
        logger.debug('Getting load path: {}'.format(path))
        return path

    def get_save_path(self, folder):
        """
        Displays a dialog for selecting a file to save. Returns the selected
        path. Defaults to start in the referenced folder.
        """
        path, _ = QFileDialog.getSaveFileName(self.widget, 'Save file', folder)
        logger.debug('Getting save path: {}'.format(path))
        return path

    def get_microbit_path(self, folder):
        """
        Displays a dialog for locating the location of the BBC micro:bit in the
        host computer's filesystem. Returns the selected path. Defaults to
        start in the referenced folder.
        """
        path = QFileDialog.getExistingDirectory(self.widget,
                                                'Locate BBC micro:bit', folder,
                                                QFileDialog.ShowDirsOnly)
        logger.debug('Getting micro:bit path: {}'.format(path))
        return path

    def add_tab(self, path, text, api):
        """
        Adds a tab with the referenced path and text to the editor.
        """
        new_tab = EditorPane(path, text)
        new_tab.connect_margin(self.breakpoint_toggle)
        new_tab_index = self.tabs.addTab(new_tab, new_tab.label)
        new_tab.set_api(api)

        @new_tab.modificationChanged.connect
        def on_modified():
            modified_tab_index = self.tabs.currentIndex()
            self.tabs.setTabText(modified_tab_index, new_tab.label)
            self.update_title(new_tab.label)

        self.tabs.setCurrentIndex(new_tab_index)
        self.connect_zoom(new_tab)
        self.set_theme(self.theme)
        new_tab.setFocus()
        if self.read_only_tabs:
            new_tab.setReadOnly(self.read_only_tabs)

    def focus_tab(self, tab):
        index = self.tabs.indexOf(tab)
        self.tabs.setCurrentIndex(index)
        tab.setFocus()

    @property
    def tab_count(self):
        """
        Returns the number of active tabs.
        """
        return self.tabs.count()

    @property
    def widgets(self):
        """
        Returns a list of references to the widgets representing tabs in the
        editor.
        """
        return [self.tabs.widget(i) for i in range(self.tab_count)]

    @property
    def modified(self):
        """
        Returns a boolean indication if there are any modified tabs in the
        editor.
        """
        for widget in self.widgets:
            if widget.isModified():
                return True
        return False

    def on_serial_read(self):
        """
        Called when the connected device is ready to send data via the serial
        connection. It reads all the available data, emits the data_received
        signal with the received bytes and, if appropriate, emits the
        tuple_received signal with the tuple created from the bytes received.
        """
        data = bytes(self.serial.readAll())  # get all the available bytes.
        self.data_received.emit(data)

    def open_serial_link(self, port):
        """
        Creates a new serial link instance.
        """
        self.input_buffer = []
        self.serial = QSerialPort()
        self.serial.setPortName(port)
        if self.serial.open(QIODevice.ReadWrite):
            self.serial.dataTerminalReady = True
            if not self.serial.isDataTerminalReady():
                # Using pyserial as a 'hack' to open the port and set DTR
                # as QtSerial does not seem to work on some Windows :(
                # See issues #281 and #302 for details.
                self.serial.close()
                pyser = serial.Serial(port)  # open serial port w/pyserial
                pyser.dtr = True
                pyser.close()
                self.serial.open(QIODevice.ReadWrite)
            self.serial.setBaudRate(115200)
            self.serial.readyRead.connect(self.on_serial_read)
        else:
            raise IOError("Cannot connect to device on port {}".format(port))

    def close_serial_link(self):
        """
        Close and clean up the currently open serial link.
        """
        self.serial.close()
        self.serial = None

    def add_filesystem(self, home, file_manager):
        """
        Adds the file system pane to the application.
        """
        self.fs_pane = FileSystemPane(home)
        self.fs = QDockWidget(_('Filesystem on micro:bit'))
        self.fs.setWidget(self.fs_pane)
        self.fs.setFeatures(QDockWidget.DockWidgetMovable)
        self.fs.setAllowedAreas(Qt.BottomDockWidgetArea)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.fs)
        self.fs_pane.setFocus()
        file_manager.on_list_files.connect(self.fs_pane.on_ls)
        self.fs_pane.list_files.connect(file_manager.ls)
        self.fs_pane.microbit_fs.put.connect(file_manager.put)
        self.fs_pane.microbit_fs.delete.connect(file_manager.delete)
        self.fs_pane.microbit_fs.list_files.connect(file_manager.ls)
        self.fs_pane.local_fs.get.connect(file_manager.get)
        self.fs_pane.local_fs.list_files.connect(file_manager.ls)
        file_manager.on_put_file.connect(self.fs_pane.microbit_fs.on_put)
        file_manager.on_delete_file.connect(self.fs_pane.microbit_fs.on_delete)
        file_manager.on_get_file.connect(self.fs_pane.local_fs.on_get)
        file_manager.on_list_fail.connect(self.fs_pane.on_ls_fail)
        file_manager.on_put_fail.connect(self.fs_pane.on_put_fail)
        file_manager.on_delete_fail.connect(self.fs_pane.on_delete_fail)
        file_manager.on_get_fail.connect(self.fs_pane.on_get_fail)
        self.connect_zoom(self.fs_pane)
        return self.fs_pane

    def add_micropython_repl(self, port, name):
        """
        Adds a MicroPython based REPL pane to the application.
        """
        if not self.serial:
            self.open_serial_link(port)
            # Send a Control-C / keyboard interrupt.
            self.serial.write(b'\x03')
        repl_pane = MicroPythonREPLPane(serial=self.serial, theme=self.theme)
        self.data_received.connect(repl_pane.process_bytes)
        self.add_repl(repl_pane, name)

    def add_micropython_plotter(self, port, name):
        """
        Adds a plotter that reads data from a serial connection.
        """
        if not self.serial:
            self.open_serial_link(port)
        plotter_pane = PlotterPane(theme=self.theme)
        self.data_received.connect(plotter_pane.process_bytes)
        self.add_plotter(plotter_pane, name)

    def add_jupyter_repl(self, kernel_manager, kernel_client):
        """
        Adds a Jupyter based REPL pane to the application.
        """
        kernel_manager.kernel.gui = 'qt4'
        kernel_client.start_channels()
        ipython_widget = JupyterREPLPane(theme=self.theme)
        ipython_widget.kernel_manager = kernel_manager
        ipython_widget.kernel_client = kernel_client
        self.add_repl(ipython_widget, _('Python3 (Jupyter)'))

    def add_repl(self, repl_pane, name):
        """
        Adds the referenced REPL pane to the application.
        """
        self.repl_pane = repl_pane
        self.repl = QDockWidget(_('{} REPL').format(name))
        self.repl.setWidget(repl_pane)
        self.repl.setFeatures(QDockWidget.DockWidgetMovable)
        self.repl.setAllowedAreas(Qt.BottomDockWidgetArea |
                                  Qt.LeftDockWidgetArea |
                                  Qt.RightDockWidgetArea)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.repl)
        self.connect_zoom(self.repl_pane)
        self.repl_pane.set_theme(self.theme)
        self.repl_pane.setFocus()

    def add_plotter(self, plotter_pane, name):
        """
        Adds the referenced plotter pane to the application.
        """
        self.plotter_pane = plotter_pane
        self.plotter = QDockWidget(_('{} Plotter').format(name))
        self.plotter.setWidget(plotter_pane)
        self.plotter.setFeatures(QDockWidget.DockWidgetMovable)
        self.plotter.setAllowedAreas(Qt.BottomDockWidgetArea |
                                     Qt.LeftDockWidgetArea |
                                     Qt.RightDockWidgetArea)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.plotter)
        self.plotter_pane.set_theme(self.theme)
        self.plotter_pane.setFocus()

    def add_python3_runner(self, script_name, working_directory,
                           interactive=False, debugger=False,
                           command_args=None, runner=None):
        """
        Display console output for the referenced Python script.

        The script will be run within the workspace_path directory.

        If interactive is True (default is False) the Python process will
        run in interactive mode (dropping the user into the REPL when the
        script completes).

        If debugger is True (default is False) the script will be run within
        a debug runner session. The debugger overrides the interactive flag
        (you cannot run the debugger in interactive mode).

        If there is a list of command_args (the default is None) then these
        will be passed as further arguments into the command run in the
        new process.

        If runner is give, this is used as the command to start the Python
        process.
        """
        self.process_runner = PythonProcessPane(self)
        self.runner = QDockWidget(_("Running: {}").format(
                                  os.path.basename(script_name)))
        self.runner.setWidget(self.process_runner)
        self.runner.setFeatures(QDockWidget.DockWidgetMovable)
        self.runner.setAllowedAreas(Qt.BottomDockWidgetArea |
                                    Qt.LeftDockWidgetArea |
                                    Qt.RightDockWidgetArea)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.runner)
        self.process_runner.start_process(script_name, working_directory,
                                          interactive, debugger, command_args,
                                          runner)
        self.process_runner.setFocus()
        self.connect_zoom(self.process_runner)
        return self.process_runner

    def add_debug_inspector(self):
        """
        Display a debug inspector to view the call stack.
        """
        self.debug_inspector = DebugInspector()
        self.debug_model = QStandardItemModel()
        self.debug_inspector.setModel(self.debug_model)
        self.debug_inspector.setUniformRowHeights(True)
        self.inspector = QDockWidget(_('Debug Inspector'))
        self.inspector.setWidget(self.debug_inspector)
        self.inspector.setFeatures(QDockWidget.DockWidgetMovable)
        self.inspector.setAllowedAreas(Qt.BottomDockWidgetArea |
                                       Qt.LeftDockWidgetArea |
                                       Qt.RightDockWidgetArea)
        self.addDockWidget(Qt.RightDockWidgetArea, self.inspector)
        self.connect_zoom(self.debug_inspector)

    def update_debug_inspector(self, locals_dict):
        """
        Given the contents of a dict representation of the locals in the
        current stack frame, update the debug inspector with the new values.
        """
        excluded_names = ['__builtins__', '__debug_code__',
                          '__debug_script__', ]
        names = sorted([x for x in locals_dict if x not in excluded_names])
        self.debug_model.clear()
        self.debug_model.setHorizontalHeaderLabels([_('Name'), _('Value'), ])
        for name in names:
            try:
                # DANGER!
                val = eval(locals_dict[name])
            except Exception:
                val = None
            if isinstance(val, list):
                # Show a list consisting of rows of position/value
                list_item = QStandardItem(name)
                for i, i_val in enumerate(val):
                    list_item.appendRow([
                        QStandardItem(str(i)),
                        QStandardItem(repr(i_val))
                    ])
                self.debug_model.appendRow([
                    list_item,
                    QStandardItem(_('(A list of {} items.)').format(len(val)))
                ])
            elif isinstance(val, dict):
                # Show a dict consisting of rows of key/value pairs.
                dict_item = QStandardItem(name)
                for k, k_val in val.items():
                    dict_item.appendRow([
                        QStandardItem(repr(k)),
                        QStandardItem(repr(k_val))
                    ])
                self.debug_model.appendRow([
                    dict_item,
                    QStandardItem(_('(A dict of {} items.)').format(len(val)))
                ])
            else:
                self.debug_model.appendRow([
                    QStandardItem(name),
                    QStandardItem(locals_dict[name]),
                ])

    def remove_filesystem(self):
        """
        Removes the file system pane from the application.
        """
        if hasattr(self, 'fs') and self.fs:
            self.fs_pane = None
            self.fs.setParent(None)
            self.fs.deleteLater()
            self.fs = None

    def remove_repl(self):
        """
        Removes the REPL pane from the application.
        """
        if self.repl:
            self.repl_pane = None
            self.repl.setParent(None)
            self.repl.deleteLater()
            self.repl = None
            if not self.plotter:
                self.serial = None

    def remove_plotter(self):
        """
        Removes the plotter pane from the application.
        """
        if self.plotter:
            self.plotter_pane = None
            self.plotter.setParent(None)
            self.plotter.deleteLater()
            self.plotter = None
            if not self.repl:
                self.serial = None

    def remove_python_runner(self):
        """
        Removes the runner pane from the application.
        """
        if hasattr(self, 'runner') and self.runner:
            self.process_runner = None
            self.runner.setParent(None)
            self.runner.deleteLater()
            self.runner = None

    def remove_debug_inspector(self):
        """
        Removes the debug inspector pane from the application.
        """
        if hasattr(self, 'inspector') and self.inspector:
            self.debug_inspector = None
            self.debug_model = None
            self.inspector.setParent(None)
            self.inspector.deleteLater()
            self.inspector = None

    def set_theme(self, theme):
        """
        Sets the theme for the REPL and editor tabs.
        """
        self.theme = theme
        if theme == 'contrast':
            self.setStyleSheet(CONTRAST_STYLE)
            new_theme = ContrastTheme
            new_icon = 'theme_day'
        elif theme == 'night':
            new_theme = NightTheme
            new_icon = 'theme_contrast'
            self.setStyleSheet(NIGHT_STYLE)
        else:
            self.setStyleSheet(DAY_STYLE)
            new_theme = DayTheme
            new_icon = 'theme'
        for widget in self.widgets:
            widget.set_theme(new_theme)
        self.button_bar.slots['theme'].setIcon(load_icon(new_icon))
        if hasattr(self, 'repl') and self.repl:
            self.repl_pane.set_theme(theme)
        if hasattr(self, 'plotter') and self.plotter:
            self.plotter_pane.set_theme(theme)

    def show_logs(self, log, theme):
        """
        Display the referenced content of the log.
        """
        log_box = LogDisplay()
        log_box.setup(log, theme)
        log_box.exec()

    def show_message(self, message, information=None, icon=None):
        """
        Displays a modal message to the user.

        If information is passed in this will be set as the additional
        informative text in the modal dialog.

        Since this mechanism will be used mainly for warning users that
        something is awry the default icon is set to "Warning". It's possible
        to override the icon to one of the following settings: NoIcon,
        Question, Information, Warning or Critical.
        """
        message_box = QMessageBox(self)
        message_box.setText(message)
        message_box.setWindowTitle('Mu')
        if information:
            message_box.setInformativeText(information)
        if icon and hasattr(message_box, icon):
            message_box.setIcon(getattr(message_box, icon))
        else:
            message_box.setIcon(message_box.Warning)
        logger.debug(message)
        logger.debug(information)
        message_box.exec()

    def show_confirmation(self, message, information=None, icon=None):
        """
        Displays a modal message to the user to which they need to confirm or
        cancel.

        If information is passed in this will be set as the additional
        informative text in the modal dialog.

        Since this mechanism will be used mainly for warning users that
        something is awry the default icon is set to "Warning". It's possible
        to override the icon to one of the following settings: NoIcon,
        Question, Information, Warning or Critical.
        """
        message_box = QMessageBox()
        message_box.setText(message)
        message_box.setWindowTitle(_('Mu'))
        if information:
            message_box.setInformativeText(information)
        if icon and hasattr(message_box, icon):
            message_box.setIcon(getattr(message_box, icon))
        else:
            message_box.setIcon(message_box.Warning)
        message_box.setStandardButtons(message_box.Cancel | message_box.Ok)
        message_box.setDefaultButton(message_box.Cancel)
        logger.debug(message)
        logger.debug(information)
        return message_box.exec()

    def update_title(self, filename=None):
        """
        Updates the title bar of the application. If a filename (representing
        the name of the file currently the focus of the editor) is supplied,
        append it to the end of the title.
        """
        title = self.title
        if filename:
            title += ' - ' + filename
        self.setWindowTitle(title)

    def autosize_window(self):
        """
        Makes the editor 80% of the width*height of the screen and centres it.
        """
        screen = QDesktopWidget().screenGeometry()
        w = int(screen.width() * 0.8)
        h = int(screen.height() * 0.8)
        self.resize(w, h)
        size = self.geometry()
        self.move((screen.width() - size.width()) / 2,
                  (screen.height() - size.height()) / 2)

    def reset_annotations(self):
        """
        Resets the state of annotations on the current tab.
        """
        self.current_tab.reset_annotations()

    def annotate_code(self, feedback, annotation_type):
        """
        Given a list of annotations about the code in the current tab, add
        the annotations to the editor window so the user can make appropriate
        changes.
        """
        self.current_tab.annotate_code(feedback, annotation_type)

    def show_annotations(self):
        """
        Show the annotations added to the current tab.
        """
        self.current_tab.show_annotations()

    def setup(self, breakpoint_toggle, theme):
        """
        Sets up the window.

        Defines the various attributes of the window and defines how the user
        interface is laid out.
        """
        self.theme = theme
        self.breakpoint_toggle = breakpoint_toggle
        # Give the window a default icon, title and minimum size.
        self.setWindowIcon(load_icon(self.icon))
        self.update_title()
        self.read_only_tabs = False
        self.setMinimumSize(800, 400)

        self.widget = QWidget()

        widget_layout = QVBoxLayout()
        self.widget.setLayout(widget_layout)
        self.button_bar = ButtonBar(self.widget)
        self.tabs = FileTabs()
        self.tabs.setMovable(True)
        self.setCentralWidget(self.tabs)
        self.status_bar = StatusBar(parent=self)
        self.setStatusBar(self.status_bar)
        self.addToolBar(self.button_bar)
        self.show()
        self.autosize_window()

    def resizeEvent(self, resizeEvent):
        """
        Respond to window getting too small for the button bar to fit well.
        """
        size = resizeEvent.size()
        self.button_bar.set_responsive_mode(size.width(), size.height())

    def select_mode(self, modes, current_mode, theme):
        """
        Display the mode selector dialog and return the result.
        """
        mode_select = ModeSelector()
        mode_select.setup(modes, current_mode, theme)
        mode_select.exec()
        try:
            return mode_select.get_mode()
        except Exception as ex:
            return None

    def change_mode(self, mode):
        """
        Given a an object representing a mode, recreates the button bar with
        the expected functionality.
        """
        self.button_bar.change_mode(mode)
        # Update the autocomplete / tooltip APIs for each tab to the new mode.
        api = mode.api()
        for widget in self.widgets:
            widget.set_api(api)

    def set_usb_checker(self, duration, callback):
        """
        Sets up a timer that polls for USB changes via the "callback" every
        "duration" seconds.
        """
        self.usb_checker = QTimer()
        self.usb_checker.timeout.connect(callback)
        self.usb_checker.start(duration * 1000)

    def set_timer(self, duration, callback):
        """
        Set a repeating timer to call "callback" every "duration" seconds.
        """
        self.timer = QTimer()
        self.timer.timeout.connect(callback)
        self.timer.start(duration * 1000)  # Measured in milliseconds.

    def stop_timer(self):
        """
        Stop the repeating timer.
        """
        if self.timer:
            self.timer.stop()
            self.timer = None

    def connect_tab_rename(self, handler, shortcut):
        """
        Connect the double-click event on a tab and the keyboard shortcut to
        the referenced handler (causing the Save As dialog).
        """
        self.tabs.shortcut = QShortcut(QKeySequence(shortcut), self)
        self.tabs.shortcut.activated.connect(handler)
        self.tabs.tabBarDoubleClicked.connect(handler)

    def open_directory_from_os(self, path):
        """
        Given the path to a directoy, open the OS's built in filesystem
        explorer for that path. Works with Windows, OSX and Linux.
        """
        if sys.platform == 'win32':
            # Windows
            os.startfile(path)
        elif sys.platform == 'darwin':
            # OSX
            os.system('open "{}"'.format(path))
        else:
            # Assume freedesktop.org on unix-y.
            os.system('xdg-open "{}"'.format(path))
class SerialSimulate(QObject):
    '''
    class SerialSimulate
    '''
    stateChanged = QtCore.pyqtSignal(str)
    serialPortError = QtCore.pyqtSignal(QSerialPort.SerialPortError, str)
    def __init__(self, parent = None):
        super(SerialSimulate, self).__init__(parent)
        self.setObjectName('SerialSimulate')
        #
        self._currIndex = 0
        self._currFrameId = 0
        self._frameSize = 0
        self._streamBuff = []
        self._newBuff = [0] * 4096
        self._pkgBuff = [0] * 100
        self._serialSend = SerialSend()
        self._serialRecv = SerialRecv()

        self._serialConfig = SerialPortConfig()
        self._serialPort = QSerialPort(self)

        #
        self._serialPort.error.connect(self.onSerialPortError)
        self._serialPort.readyRead.connect(self.readData)

        #
        self._serialPort.setPortName('COM5')
        if self._serialPort.open(QIODevice.ReadWrite):
            self._serialPort.setBaudRate(QSerialPort.Baud115200)
            self._serialPort.setDataBits(QSerialPort.Data8)
            self._serialPort.setParity(QSerialPort.OddParity)
            self._serialPort.setStopBits(QSerialPort.OneStop)
            self.stateChanged.emit('Open')

        #
        self._serialRecv.lMBrakeP = SerialPortProxy.swapUint16(0)
        self._serialRecv.rMBrakeP = SerialPortProxy.swapUint16(0)
        self._serialRecv.lABrakeP = SerialPortProxy.swapUint16(5)
        self._serialRecv.rABrakeP = SerialPortProxy.swapUint16(5)
        self._serialRecv.lMRotateP = SerialPortProxy.swapUint16(0)
        self._serialRecv.rMRotateP = SerialPortProxy.swapUint16(0)
        self._serialRecv.lARotateP = SerialPortProxy.swapUint16(5)
        self._serialRecv.rARotateP = SerialPortProxy.swapUint16(5)
        self._serialRecv.lWheelSpd = self.convertToASCII(100)
        self._serialRecv.rWheelSpd = self.convertToASCII(100)

        #
        self._timerId = self.startTimer(100, Qt.PreciseTimer)

    @QtCore.pyqtSlot(QSerialPort.SerialPortError, str)
    def onSerialPortError(self, error):
        print('SerialPort open failed!, %d' % error)
        self.serialPortError.emit(error,
                                  'No error' if error == QSerialPort.NoError
                                  else 'Device not found' if error == QSerialPort.DeviceNotFoundError
                                  else 'Permission error' if error == QSerialPort.PermissionError
                                  else 'Open error' if error == QSerialPort.OpenError
                                  else 'Parity error' if error == QSerialPort.ParityError
                                  else 'Framing error' if error == QSerialPort.FramingError
                                  else 'Break Condition error' if error == QSerialPort.BreakConditionError
                                  else 'Write error' if error == QSerialPort.WriteError
                                  else 'Read error' if error == QSerialPort.ReadError
                                  else 'Resource error' if error == QSerialPort.ResourceError
                                  else 'Unsupported operation' if error == QSerialPort.UnsupportedOperationError
                                  else 'Unknown error' if error == QSerialPort.UnknownError
                                  else 'Timeout' if error == QSerialPort.TimeoutError
                                  else 'Not open' if error == QSerialPort.NotOpenError
                                  else '%d' % error)

    @QtCore.pyqtSlot()
    def start(self):
        if self._serialPort.isOpen():
            self._serialPort.close()

        # config serialport properties
        self._serialPort.setPortName(self._serialConfig.port)
        if self._serialPort.open(QIODevice.ReadWrite):
            self._serialPort.setBaudRate(self._serialConfig.baudRate)
            self._serialPort.setDataBits(self._serialConfig.dataBits)
            self._serialPort.setParity(self._serialConfig.parity)
            self._serialPort.setStopBits(self._serialConfig.stopBits)
            self.stateChanged.emit('Open')

    @QtCore.pyqtSlot()
    def stop(self):
        if self._serialPort.isOpen():
            self._serialPort.close()
            self.stateChanged.emit('Close')

    @QtCore.pyqtSlot()
    def save(self):
        self.setProperty('portState', self._serialPort.isOpen())
        self.stop()

    @QtCore.pyqtSlot()
    def restore(self):
        self.start() if bool(self.property('portState')) else self.stop()

    @QtCore.pyqtSlot(SerialRecv)
    def writeData(self, data):
        if not self._serialPort.isOpen():
            # warning...
            self.killTimer(self._timerId)
            return 0
        return int(self._serialPort.write(data.pack()))

    @QtCore.pyqtSlot()
    def readData(self):
        self._streamBuff = self._serialPort.read(4096)
        self.unpack()
        return self._streamBuff.__len__()

    def unpack(self):
        for (i, value) in enumerate(self._streamBuff):
            if self._currIndex < self._serialSend._offset_length:  # 1.frame-header
                self._frameSize = 0
                if value == self._serialSend._headers[self._currIndex]:
                    self._newBuff[self._currIndex] = value
                    self._currIndex += 1
                else:
                    self._currIndex = 0
                continue
            elif self._currIndex == self._serialSend._offset_length:  # 2.frame-length
                if value == self._serialSend.length:
                    pass
                else:
                    self._currIndex = 0
                    continue
                self._frameSize = value
                self._newBuff[i] = value
                self._currIndex += 1
                continue
            elif self._currIndex == self._serialSend._offset_index:  # 3.frame-index
                self._currFrameId = value
                self._newBuff[i] = value
                self._currIndex += 1
                continue
            elif self._currIndex < self._frameSize:  # 4.frame-data
                self._newBuff[i] = value
                self._currIndex += 1
            if self._currIndex == self._frameSize:  # receive a full frame successfully
                # 5.frame-sum
                s = 0
                for index in range(0, self._serialSend._offset_sum):
                    s = (s + self._newBuff[index]) & 0xff
                if self._newBuff[self._serialSend._offset_sum] != s:
                    self._currIndex = 0
                    # continue  # invalid frame
                # 6.frame-tail
                if self._newBuff[self._serialSend._offset_tail] != int(self._serialSend.tail):
                    self._currIndex = 0  # invalid frame
                    continue
                # 7.save as...
                self._pkgBuff = self._newBuff[0:self._frameSize]
                # 8.dispatch
                self.dispatch()
                # 9.reset
                self._currIndex = 0

    def dispatch(self):
        # save as...
        self._serialSend.unpack(bytes(self._pkgBuff))

        # send
        self._serialRecv.lWheelSpd = self.convertToASCII(int(self._serialSend.lWheelSpd / 42.94967296))
        self._serialRecv.rWheelSpd = self.convertToASCII(int(self._serialSend.rWheelSpd / 42.94967296))
        self._serialRecv.sum = SerialPortProxy.serialPortRecvSum(self._serialRecv)
        self.writeData(self._serialRecv)

    def timerEvent(self, event):
        step = 1
        if event.timerId() == self._timerId:
            self._serialRecv.index += 1
            if self._serialSend.ctrlWord.lPowerSw:
                self._serialRecv.lMBrakeP = self.stepInc(self._serialRecv.lMBrakeP, step, 30)
                self._serialRecv.lABrakeP = self.stepInc(self._serialRecv.lABrakeP, step, 30)
                self._serialRecv.lMRotateP = self.stepInc(self._serialRecv.lMRotateP, step, 30)
                self._serialRecv.lARotateP = self.stepInc(self._serialRecv.lARotateP, step, 30)
                self._serialRecv.lWheelSpd = self.stepInc(self._serialRecv.lWheelSpd, step, 3000)
            if self._serialSend.ctrlWord.rPowerSw:
                self._serialRecv.rMBrakeP = self.stepInc(self._serialRecv.rMBrakeP, step, 30)
                self._serialRecv.rABrakeP = self.stepInc(self._serialRecv.rABrakeP, step, 30)
                self._serialRecv.rMRotateP = self.stepInc(self._serialRecv.rMRotateP, step, 30)
                self._serialRecv.rARotateP = self.stepInc(self._serialRecv.rARotateP, step, 30)
                self._serialRecv.rWheelSpd = self.stepInc(self._serialRecv.rWheelSpd, step, 3000)
            self._serialRecv.sum = SerialPortProxy.serialPortRecvSum(self._serialRecv)
            self.writeData(self._serialRecv)

    @staticmethod
    def stepWheelSpd(value, step, maxValue):
        value = SerialPortProxy.convertFromASCII(value) + step
        if value > maxValue:
            value = 0
        return SerialSimulate.convertToASCII(value)

    @staticmethod
    def convertToASCII(value):
        return value

    @staticmethod
    def stepInc(value, step, maxValue):
        value = SerialPortProxy.swapUint16(value) + step  # + random() % 50
        if value > maxValue:
            value = 0
        return SerialPortProxy.swapUint16(value)
    def __init__(self, parent=None):
        super(SerialPortProxy, self).__init__(parent)
        self.setObjectName("SerialPortProxy")

        #
        self._currIndex = 0
        self._currFrameId = 0
        self._frameSize = 0
        self._streamBuff = []
        self._newBuff = [0] * 4096
        self._pkgBuff = [0] * 100
        self._serialRecv = SerialRecv()

        self._serialConfig = SerialPortConfig()
        self._serialPort = QSerialPort(self)

        #
        self._serialPort.error.connect(self.onSerialPortError)
        self._serialPort.readyRead.connect(self.readData)

        #
        self._serialSimulate = None  # SerialSimulate(self)

        # read configuration
        settings = QSettings(self)
        # group - serialport properties
        settings.beginGroup("Settings/" + self.objectName() + "/SerialPort")
        self._serialConfig.port = settings.value("port", "COM1")
        infolist = settings.value("info", "115200-8-N-1").split("-")
        self._serialConfig.baudRate = int(infolist[0])
        dataBits = int(infolist[1])
        self._serialConfig.dataBits = (
            QSerialPort.Data5
            if dataBits == 5
            else QSerialPort.Data6
            if dataBits == 6
            else QSerialPort.Data7
            if dataBits == 7
            else QSerialPort.Data8
            if dataBits == 8
            else QSerialPort.Data8
        )
        parity = infolist[2][0].upper()
        self._serialConfig.parity = (
            QSerialPort.NoParity
            if parity == "N"
            else QSerialPort.EvenParity
            if parity == "E"
            else QSerialPort.OddParity
            if parity == "O"
            else QSerialPort.SpaceParity
            if parity == "S"
            else QSerialPort.MarkParity
            if parity == "M"
            else QSerialPort.NoParity
        )
        stopBits = int(float(infolist[3]) * 10)
        self._serialConfig.stopBits = (
            QSerialPort.OneStop
            if stopBits == 10
            else QSerialPort.OneAndHalfStop
            if stopBits == 15
            else QSerialPort.TwoStop
            if stopBits == 20
            else QSerialPort.OneStop
        )
        settings.endGroup()
Exemple #51
0
class REPLPane(QTextEdit):
    """
    REPL = Read, Evaluate, Print, Loop.

    This widget represents a REPL client connected to a BBC micro:bit.
    """

    def __init__(self, port, parent=None):
        super().__init__(parent)
        self.setAcceptRichText(False)
        self.setReadOnly(False)
        self.setLineWrapMode(QTextEdit.NoWrap)
        self.setObjectName("replpane")
        # A flag to indicate that we've sent some sort of escape
        # character e.g. \b
        self.escape_flag = False

        # open the serial port
        self.serial = QSerialPort(self)
        self.serial.setPortName(port)
        self.serial.setBaudRate(115200)
        print(self.serial.open(QIODevice.ReadWrite))
        self.serial.readyRead.connect(self.on_serial_read)

        # clear the text
        self.clear()

    def on_serial_read(self):
        self.append(self.serial.readAll())

    def keyPressEvent(self, data):
        self.escape_flag = False
        text = data.text()
        msg = bytes(text, "utf8")
        key = data.key()
        if key == Qt.Key_Backspace:
            msg = "\b"
            self.delete()
            self.escape_flag = True
        elif key == Qt.Key_Up:
            msg = "\x1B[A"
        elif key == Qt.Key_Down:
            msg = "\x1B[B"
        self.serial.write(msg)

    def append(self, data):
        txt = str(data, "utf8")
        if self.escape_flag:
            return
        tc = self.textCursor()
        tc.movePosition(QTextCursor.End)
        self.setTextCursor(tc)
        self.insertPlainText(txt)
        self.ensureCursorVisible()

    def delete(self):
        tc = self.textCursor()
        block_text = tc.block().text()
        if not (block_text.startswith(">>> ") or block_text.startswith("... ")):
            return
        if block_text in [">>> ", "... "]:
            return
        tc.deletePreviousChar()

    def clear(self):
        self.setText("")

    def kill(self):
        if self.serial.isOpen():
            self.serial.close()