Thursday, 28 June 2018

Popen read data before CTRL+C command is issued

I have a command line tool written in C for windows that scans for bluetooth devices via a serial USB Dongle.

It will loop through all devices in range repeating until it receives a CTRL+C command.

device1 name firmware
device2 name firmware
device3 name firmware
device1 name firmware
device2 name firmware
device3 name firmware
...

I want to stop the scan when it reaches a certain device so I can issue an update firmware command.

At the moment I can only capture the output after the CTRL+C command is issued using the following function that starts the scan, sleeps, then issues the CTRL+C command, I then catch the error and process the output in the except block:

        command = [self.cli_tool, '-s']

        startupinfo = subprocess.STARTUPINFO()
        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
        startupinfo.wShowWindow = subprocess.SW_HIDE

        stream = []

        if self.check_dongle_firmware() is not False:
            try:                    
                self.proc = subprocess.Popen(
                            command, 
                            stdin=subprocess.PIPE, 
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.DEVNULL, 
                            startupinfo=startupinfo)

                time.sleep(SCAN_TIMEOUT)
                os.kill(self.proc.pid, signal.CTRL_C_EVENT)
                self.proc.wait()

            except KeyboardInterrupt:                
                for line in self.proc.stdout:
                    stream.append(line)                         

                for x in stream[7:]:
                    x = x.decode()
                    print(x.strip())   

I want something like this:

stream = []

 self.proc = subprocess.Popen(
                            command, stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.DEVNULL, 
                            startupinfo=startupinfo)

for line in self.proc.stdout:
    stream.append(line) 
    if 'device2' in line.decode().split():
        os.kill(self.proc.pid, signal.CTRL_C_EVENT)
        self.proc.wait()

This does not work though. It will not read 1 line at a time.

I need to read and process 1 line at a time so that i can stop the process at a certain device.

currently it only reads an empty byte or string depending on the pipe attributes.

I tried various combinations using :

universal_newlines=True

bufsize=1

self.proc.communicate()[0]

When I try the code using a command like ping I have no problem and full control of the output.

I have searched SO for tried anything that looks similar but nothing works for what I need.

I think I am missing something obvious or it is not possible due to the tool not applying a flush command in the C code?

Any direction or advice is appreciated!



from Popen read data before CTRL+C command is issued

No comments:

Post a Comment