Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Correctly use QProcess to read stdout and write stdin
Forum Updated to NodeBB v4.3 + New Features

Correctly use QProcess to read stdout and write stdin

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 4 Posters 2.0k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    MNorvalls
    wrote on 9 Jul 2020, 19:26 last edited by
    #1

    Hello,

    I am trying to automate programming of an FPGA in a Qt application. I need to use Xilinx Vivado to control a Xilinx programming pod to program the FPGA.

    There aren't any API plugins they offer that I know of, but the Vivado tool has a command line option. I am trying to start the vivado_lab.exe with 3 arguments and a specific environment needed to run, as a QProcess. I have setup the environment with QProcessEnvironment object, but I get no output when running the code. I know the tool starts, as I can find its PID from windows when I run my code. But when I try to read the stdout of the process I see no output. I am expecting the command line prompt "vivado_lab%".

    The code I am referring to is below, and runs inside of a thread.

                QProcess vivadoConn;
                vivadoConn.setProcessChannelMode(QProcess::MergedChannels);
    
                // Command to start vivado in tcl mode
                //QString vivadoCmd = l_toolDirs.xilinxToolDir.toUtf8() + " -nojournal -nolog -mode tcl";
    
                // Start the Vivado command line
                if(l_testInProgress)
                {
                    emit updateTestProgressText("Starting Vivado, Please wait...\n");
    
                    QStringList args;
                    args.append("-mode tcl");
                    args.append("-nojournal");
                    args.append("-nolog");
    
                    QProcessEnvironment vivadoEnv;
                    vivadoEnv.insert("HDI_APPROOT","C:/Xilinx/Vivado_Lab/2018.2");
                    vivadoEnv.insert("RDI_APPROOT","C:/Xilinx/Vivado_Lab/2018.2");
                    vivadoEnv.insert("RT_LIBPATH","C:/Xilinx/Vivado_Lab/2018.2/scripts/rt/data");
                    vivadoEnv.insert("RT_TCL_PATH","C:/Xilinx/Vivado_Lab/2018.2/scripts/rt/base_tcl/tcl");
                    vivadoEnv.insert("TCL_LIBRARY","C:/Xilinx/Vivado_Lab/2018.2/tps/tcl/tcl8.5");
                    vivadoEnv.insert("XILINX_PLANAHEAD","C:/Xilinx/Vivado_Lab/2018.2");
                    vivadoEnv.insert("XILINX_VIVADO","C:/Xilinx/Vivado_Lab/2018.2");
                    vivadoEnv.insert("Path","C:/Xilinx/Vivado_Lab/2018.2/bin;C:/Xilinx/Vivado_Lab/2018.2/lib/win64.o;C:/Xilinx/Vivado_Lab/2018.2/tps/win64/jre/bin/server;C:/Xilinx/Vivado_Lab/2018.2/tps/win64/jre/bin;");
    
                    QString xilinxvivadoResp, test1;
                    //vivadoConn.setProgram(l_toolDirs.xilinxToolDir.toUtf8());
                    vivadoConn.setProcessEnvironment(vivadoEnv);
                    //vivadoConn.setArguments(args);
                    vivadoConn.start(l_toolDirs.xilinxToolDir.toUtf8() + " -nojournal -nolog -mode tcl");
    
                    vivadoConn.waitForStarted();
    
                    qint64 vivado_pid = 0;
                    vivado_pid = FindProcessId(L"vivado_lab.exe");
    
                    xilinxvivadoResp = vivadoConn.readAllStandardOutput();
                    test1 = vivadoConn.readAllStandardError();
                    while(vivadoConn.waitForReadyRead(1000)) xilinxvivadoResp += vivadoConn.readAllStandardOutput();
    
                    emit updateTestProgressText("Output String: " + xilinxvivadoResp + "\n");
                    emit updateTestProgressText("Error String: " + test1 + "\n");
    
                    emit updateTestProgressText("Process ID for Vivado is: " + QString::number(vivado_pid) + "\n");
    
                    if((!xilinxvivadoResp.contains("vivado_lab%")) || (vivadoConn.state() == QProcess::ProcessState::NotRunning))
                    {
                        emit updateTestProgressText("Error connecting to Xilinx Vivado!\n\nExiting!\n");
                        vivadoConn.write("exit");
                        vivadoConn.kill();
                        threadStopping();
                        return;
                    }
    
                    // Increment progress
                    for(auto i = 10; i <= 20; i++)
                    {
                        emit updateTestProgress(i);
                    }
                }
    
                // Open a connection to the Xilinx pod hardware from vivado
                if(l_testInProgress)
                {
                    vivadoConn.write("open_hw");
                    this->sleep(3); // Wait for app response
    
                    QString xilinxvivadoResp = vivadoConn.readAll();
    
                    if((!xilinxvivadoResp.contains("vivado_lab%")) || (vivadoConn.state() == QProcess::ProcessState::NotRunning))
                    {
                        emit updateTestProgressText("Error opening Xilinx hardware!\n\nExiting!\n");
                        vivadoConn.write("exit");
                        vivadoConn.kill();
                        threadStopping();
                        return;
                    }
    
                    // Increment progress
                    for(auto i = 20; i <= 30; i++)
                    {
                        emit updateTestProgress(i);
                    }
                }
    
                // Connect to the new Xilinx hardware connection
                if(l_testInProgress)
                {
                    vivadoConn.write("connect_hw_server");
                    QThread::sleep(10); // Wait for app response
    
                    QString xilinxvivadoResp = vivadoConn.readAll();
    
                    if((!xilinxvivadoResp.contains("connect_hw_server: Time")) || (vivadoConn.state() == QProcess::ProcessState::NotRunning))
                    {
                        emit updateTestProgressText("Error connecting to Xilinx hardware!\n\nExiting!\n");
                        vivadoConn.write("exit");
                        vivadoConn.kill();
                        threadStopping();
                        return;
                    }
    
                    // Increment progress
                    for(auto i = 30; i <= 40; i++)
                    {
                        emit updateTestProgress(i);
                    }
                }
    
                // Check for Xilinx devices
                if(l_testInProgress)
                {
                    vivadoConn.write("get_hw_devices");
                    QThread::sleep(5); // Wait for app response
    
                    QString xilinxvivadoResp = vivadoConn.readAll();
    
                    if((!xilinxvivadoResp.contains("No matching hw_devices were found")) || (vivadoConn.state() == QProcess::ProcessState::NotRunning))
                    {
                        emit updateTestProgressText("Error: Could not find Xilinx FPGA!\n\nExiting!\n");
                        vivadoConn.write("exit");
                        vivadoConn.kill();
                        threadStopping();
                        return;
                    }
    
                    // Increment progress
                    for(auto i = 40; i <= 50; i++)
                    {
                        emit updateTestProgress(i);
                    }
                }
                threadStopping();
    
    J 1 Reply Last reply 10 Jul 2020, 17:43
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 9 Jul 2020, 19:52 last edited by
      #2

      Hi and welcome to devnet,

      Did you try using the asynchronous API ?
      What about passing the parameters as a QStringList as is recommended ? Does it yield the same result ?

      There's no error checks done, you should add them.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      2
      • M Offline
        M Offline
        MNorvalls
        wrote on 9 Jul 2020, 20:00 last edited by
        #3

        Hi @SGaist, thanks for the reply!

        I can't use the asynchronous as I cannot proceed to other commands and hardware controls until I can verify these commands have taken successfully. I had also tried passing the QStringList as the second argument into start() and also tried adding QIODevice::ReadWrite as the third arg as well.

        What Error checks are you referring to? Error checks in the QProcess object?

        I did try "emit updateTestProgressText("QProcess Error: " + vivadoConn.errorString());" and got "QProcess Error: Process operation timed out"

        I should add that I can run the same program with the same arguments and environment in a batch script in windows, and get the tool command line to show.

        Thank you for your time!

        1 Reply Last reply
        0
        • S Offline
          S Offline
          SGaist
          Lifetime Qt Champion
          wrote on 9 Jul 2020, 20:02 last edited by
          #4

          @MNorvalls said in Correctly use QProcess to read stdout and write stdin:

          and get the tool command line to show.

          What do you mean by that ?

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • M Offline
            M Offline
            MNorvalls
            wrote on 9 Jul 2020, 20:10 last edited by
            #5

            Running this executable from the command prompt has the tool execute a CLI based TCL command line to interface with their Xilinx tools. You can tell the tool command line is active because instead of the cmd prompt "C:/>", the tool prompt becomes "vivado_lab%", that is what I mean by getting the tool command to show.

            Does that make sense? I have also included a screenshot below :)

            7e0e8c17-f019-48ed-a566-09419d9a5cee-image.png

            1 Reply Last reply
            0
            • S Offline
              S Offline
              SGaist
              Lifetime Qt Champion
              wrote on 9 Jul 2020, 20:47 last edited by
              #6

              One thing I just saw, split the "-mode" and "tcl" in the argument list. Each element that appears on the command line is a separate element of the list.

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              1
              • M Offline
                M Offline
                MNorvalls
                wrote on 9 Jul 2020, 22:44 last edited by
                #7

                So, I was not using the argument list in that snippet of code but had tried it before and it didn't work. With your suggestion, the arguments now work (process does not crash immediately). I was tagging them onto the command string because I could get the process to run before in that case. I assume passing the arguments in a QStringList is the proper way to use QProcess::start() so I will use that moving forward.

                I have tried both of these argument methods and they both run because if I change the mode to gui, I get the Xilinx GUI window after a short amount of time.

                Unfortunately, passing arguments the way you recommended still yields no output when reading.

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on 10 Jul 2020, 17:27 last edited by
                  #8

                  Does it open it in a new command line window or in the same one that you call the application in ?

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  1 Reply Last reply
                  0
                  • M MNorvalls
                    9 Jul 2020, 19:26

                    Hello,

                    I am trying to automate programming of an FPGA in a Qt application. I need to use Xilinx Vivado to control a Xilinx programming pod to program the FPGA.

                    There aren't any API plugins they offer that I know of, but the Vivado tool has a command line option. I am trying to start the vivado_lab.exe with 3 arguments and a specific environment needed to run, as a QProcess. I have setup the environment with QProcessEnvironment object, but I get no output when running the code. I know the tool starts, as I can find its PID from windows when I run my code. But when I try to read the stdout of the process I see no output. I am expecting the command line prompt "vivado_lab%".

                    The code I am referring to is below, and runs inside of a thread.

                                QProcess vivadoConn;
                                vivadoConn.setProcessChannelMode(QProcess::MergedChannels);
                    
                                // Command to start vivado in tcl mode
                                //QString vivadoCmd = l_toolDirs.xilinxToolDir.toUtf8() + " -nojournal -nolog -mode tcl";
                    
                                // Start the Vivado command line
                                if(l_testInProgress)
                                {
                                    emit updateTestProgressText("Starting Vivado, Please wait...\n");
                    
                                    QStringList args;
                                    args.append("-mode tcl");
                                    args.append("-nojournal");
                                    args.append("-nolog");
                    
                                    QProcessEnvironment vivadoEnv;
                                    vivadoEnv.insert("HDI_APPROOT","C:/Xilinx/Vivado_Lab/2018.2");
                                    vivadoEnv.insert("RDI_APPROOT","C:/Xilinx/Vivado_Lab/2018.2");
                                    vivadoEnv.insert("RT_LIBPATH","C:/Xilinx/Vivado_Lab/2018.2/scripts/rt/data");
                                    vivadoEnv.insert("RT_TCL_PATH","C:/Xilinx/Vivado_Lab/2018.2/scripts/rt/base_tcl/tcl");
                                    vivadoEnv.insert("TCL_LIBRARY","C:/Xilinx/Vivado_Lab/2018.2/tps/tcl/tcl8.5");
                                    vivadoEnv.insert("XILINX_PLANAHEAD","C:/Xilinx/Vivado_Lab/2018.2");
                                    vivadoEnv.insert("XILINX_VIVADO","C:/Xilinx/Vivado_Lab/2018.2");
                                    vivadoEnv.insert("Path","C:/Xilinx/Vivado_Lab/2018.2/bin;C:/Xilinx/Vivado_Lab/2018.2/lib/win64.o;C:/Xilinx/Vivado_Lab/2018.2/tps/win64/jre/bin/server;C:/Xilinx/Vivado_Lab/2018.2/tps/win64/jre/bin;");
                    
                                    QString xilinxvivadoResp, test1;
                                    //vivadoConn.setProgram(l_toolDirs.xilinxToolDir.toUtf8());
                                    vivadoConn.setProcessEnvironment(vivadoEnv);
                                    //vivadoConn.setArguments(args);
                                    vivadoConn.start(l_toolDirs.xilinxToolDir.toUtf8() + " -nojournal -nolog -mode tcl");
                    
                                    vivadoConn.waitForStarted();
                    
                                    qint64 vivado_pid = 0;
                                    vivado_pid = FindProcessId(L"vivado_lab.exe");
                    
                                    xilinxvivadoResp = vivadoConn.readAllStandardOutput();
                                    test1 = vivadoConn.readAllStandardError();
                                    while(vivadoConn.waitForReadyRead(1000)) xilinxvivadoResp += vivadoConn.readAllStandardOutput();
                    
                                    emit updateTestProgressText("Output String: " + xilinxvivadoResp + "\n");
                                    emit updateTestProgressText("Error String: " + test1 + "\n");
                    
                                    emit updateTestProgressText("Process ID for Vivado is: " + QString::number(vivado_pid) + "\n");
                    
                                    if((!xilinxvivadoResp.contains("vivado_lab%")) || (vivadoConn.state() == QProcess::ProcessState::NotRunning))
                                    {
                                        emit updateTestProgressText("Error connecting to Xilinx Vivado!\n\nExiting!\n");
                                        vivadoConn.write("exit");
                                        vivadoConn.kill();
                                        threadStopping();
                                        return;
                                    }
                    
                                    // Increment progress
                                    for(auto i = 10; i <= 20; i++)
                                    {
                                        emit updateTestProgress(i);
                                    }
                                }
                    
                                // Open a connection to the Xilinx pod hardware from vivado
                                if(l_testInProgress)
                                {
                                    vivadoConn.write("open_hw");
                                    this->sleep(3); // Wait for app response
                    
                                    QString xilinxvivadoResp = vivadoConn.readAll();
                    
                                    if((!xilinxvivadoResp.contains("vivado_lab%")) || (vivadoConn.state() == QProcess::ProcessState::NotRunning))
                                    {
                                        emit updateTestProgressText("Error opening Xilinx hardware!\n\nExiting!\n");
                                        vivadoConn.write("exit");
                                        vivadoConn.kill();
                                        threadStopping();
                                        return;
                                    }
                    
                                    // Increment progress
                                    for(auto i = 20; i <= 30; i++)
                                    {
                                        emit updateTestProgress(i);
                                    }
                                }
                    
                                // Connect to the new Xilinx hardware connection
                                if(l_testInProgress)
                                {
                                    vivadoConn.write("connect_hw_server");
                                    QThread::sleep(10); // Wait for app response
                    
                                    QString xilinxvivadoResp = vivadoConn.readAll();
                    
                                    if((!xilinxvivadoResp.contains("connect_hw_server: Time")) || (vivadoConn.state() == QProcess::ProcessState::NotRunning))
                                    {
                                        emit updateTestProgressText("Error connecting to Xilinx hardware!\n\nExiting!\n");
                                        vivadoConn.write("exit");
                                        vivadoConn.kill();
                                        threadStopping();
                                        return;
                                    }
                    
                                    // Increment progress
                                    for(auto i = 30; i <= 40; i++)
                                    {
                                        emit updateTestProgress(i);
                                    }
                                }
                    
                                // Check for Xilinx devices
                                if(l_testInProgress)
                                {
                                    vivadoConn.write("get_hw_devices");
                                    QThread::sleep(5); // Wait for app response
                    
                                    QString xilinxvivadoResp = vivadoConn.readAll();
                    
                                    if((!xilinxvivadoResp.contains("No matching hw_devices were found")) || (vivadoConn.state() == QProcess::ProcessState::NotRunning))
                                    {
                                        emit updateTestProgressText("Error: Could not find Xilinx FPGA!\n\nExiting!\n");
                                        vivadoConn.write("exit");
                                        vivadoConn.kill();
                                        threadStopping();
                                        return;
                                    }
                    
                                    // Increment progress
                                    for(auto i = 40; i <= 50; i++)
                                    {
                                        emit updateTestProgress(i);
                                    }
                                }
                                threadStopping();
                    
                    J Offline
                    J Offline
                    JonB
                    wrote on 10 Jul 2020, 17:43 last edited by JonB 7 Oct 2020, 17:45
                    #9

                    @MNorvalls said in Correctly use QProcess to read stdout and write stdin:

                    I am expecting the command line prompt "vivado_lab%".

                    It may be that the shell will not send an output prompt if it detects that standard input is not a terminal.

                    Outside of Qt, you should be able to test redirecting stdin or stdout from/to a pipe (<, >, |) to see what can actually be captured.

                    And you should be capturing stderr as well as stin/out, if you are not doing so already.

                    1 Reply Last reply
                    0
                    • Christian EhrlicherC Offline
                      Christian EhrlicherC Offline
                      Christian Ehrlicher
                      Lifetime Qt Champion
                      wrote on 10 Jul 2020, 19:15 last edited by
                      #10

                      @MNorvalls said in Correctly use QProcess to read stdout and write stdin:

                      args.append("-mode tcl");

                      This is wrong, they're two arguments.

                      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                      Visit the Qt Academy at https://academy.qt.io/catalog

                      J 1 Reply Last reply 10 Jul 2020, 19:41
                      0
                      • Christian EhrlicherC Christian Ehrlicher
                        10 Jul 2020, 19:15

                        @MNorvalls said in Correctly use QProcess to read stdout and write stdin:

                        args.append("-mode tcl");

                        This is wrong, they're two arguments.

                        J Offline
                        J Offline
                        JonB
                        wrote on 10 Jul 2020, 19:41 last edited by
                        #11

                        @Christian-Ehrlicher We've moved on from that now, Christian :)

                        1 Reply Last reply
                        0
                        • M Offline
                          M Offline
                          MNorvalls
                          wrote on 4 Aug 2020, 21:22 last edited by
                          #12

                          Thanks guys, yes it seems to be the executable that does not want to output its stdout in the tcl mode. I can see output if I call it in GUI mode (but obviously the GUI starts up instead). I am just going to have it write output to a file unfortunately.

                          @SGaist The tcl command line opens in the same command window. When calling the GUI mode, some output shows in the command window, and then the GUI appears in its own window.

                          @JonB I will give the command line piping a try as well for curiosity's sake, thank you.

                          Thanks for the help!

                          1 Reply Last reply
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved