简体   繁体   中英

How can I write file line-by-line with pyserial to com0com?

I cannot write more than one line of data from a file to a virtual com port (com0com) using pyserial. I am attempting to write the file line-by-line so I can simultaneously update a progress bar in Tkinter. I am running on Windows and have attempted to put the write operation in its own thread (per UART Controller with Tkinter and Python GUI ). My program hangs after writing one line.

Relevant Code:

import os
import sys
from functools import partial
import re
import time
import threading

import serial
import serial.tools.list_ports

import tkinter as tk
from tkinter import ttk, filedialog

class MainApp(tk.Tk):

    def __init__(self,
                 parent,
                 title = 'Main Application',
                 *args,
                 **kwargs):

        self.parent = parent

        #Set window title and size
        self.parent.title(title)

        #Create widget container
        container = tk.Frame(self.parent)

        #Add widgets

        # --> Create load program widgets
        load_frame = tk.LabelFrame(container,
                                   text = 'Load Program',
                                   width = 400,
                                   height = 100)

        port_dropdown = DropDown(load_frame,
                                 label = 'Port:',
                                 row = 0)

        file_browser = Browser(load_frame,
                               path_type = 'file',
                               label = 'File:',
                               row = 1)

        program_downloader = Downloader(load_frame,
                                        port_dropdown,
                                        file_browser,
                                        row = 2)

        # --> Layout load program widgets
        load_frame.grid(row = 0,
                        column= 0,
                        padx = (5,5),
                        pady = (5,5))

        #Layout widget container
        container.pack(fill = tk.BOTH,
                       padx = 10,
                       pady = 5,
                       expand = True)         
.
.
.

class Downloader(tk.Frame):

    def __init__(self,
                 parent,
                 port_dropdown,
                 file_browser,
                 row = 0):

        self.port_dropdown = port_dropdown
        self.file_browser = file_browser

        #Instantiate serial port object
        self.serial_port = None

        self.progress_bar = ttk.Progressbar(parent,
                                            orient = 'horizontal',
                                            mode = 'determinate')

        self.progress_bar.grid(row = row,
                               column = 0,
                               columnspan = 2,
                               padx = (5,5),
                               pady = (5,5),
                               sticky = 'WE')

        self.button = tk.Button(parent,
                                text = 'Download',
                                command = self.download_program)

        self.button.grid(row = row,
                         column = 2,
                         padx = (5,5),
                         pady = (5,5),
                         sticky = 'W')

    def download_program(self):

        port_full_name = self.port_dropdown.combobox.get()
        port_name = re.match('([^\s]+)', port_full_name).group(0)

        baud_rate = 9600

        program_path = self.file_browser.text.get()

        self.connect(port_name,
                     baud_rate,
                     program_path)

    def connect(self,
                port_name,
                baud_rate,
                program_path):

        self.serial_port = serial.Serial(port_name,
                                         baud_rate,
                                         timeout=1)

        t1 = threading.Thread(target = self.transfer_data,
                              args = (program_path,))
        t1.daemon = True
        t1.start()

    def transfer_data(self,
                      program_path):

        line = 1
        self.progress_bar['value'] = line

        with open(program_path, 'r') as program:

            max_lines = len(program.readlines())
            self.progress_bar['maximum'] = max_lines

        with open(program_path, 'r') as program:

            while line < max_lines:

                command = program.readline().replace('\n','\r\n')

                print(str(line) + ': ' + repr(command))

                self.serial_port.write(command.encode('ascii'))

                line += 1

                self.progress_bar['value'] = line

                self.serial_port.flush()

        print('done')
        self.disconnect()

    def disconnect(self):
        self.serial_port.close()

if __name__ == '__main__':

    #Initialize Tkinter
    root = tk.Tk()

    #Create GUI
    gui = MainApp(root,
                  'Main Application')

    #Run program
    root.mainloop()

GUI Hangs:

图形用户界面输出

Terminal Output:

1: '@01\r\n'
2: '@02\r\n'

The fact that I'm able to read from program.txt the second time around in the loop tells me the program might be hanging because the port is still stuck on the first write.

Any help would be appreciated.

Set timeout and write_timeout to 0 prevents blocking, which seems to fix the problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM