How to open more than once SerialPort



  • Hello, I'm new on forum and QT :)
    I create a application which connect via serial port with devices. I have a problem with connect more than one device via serialport.
    I use code from example.

    void MainWindow::openSerialPort()
    {
        SettingsDialog::Settings p = settings->settings();
        serial->setPortName(p.name);
        serial->setBaudRate(QSerialPort::Baud9600);
        serial->setDataBits(QSerialPort::Data8);
        serial->setParity(QSerialPort::NoParity);
        serial->setStopBits(QSerialPort::OneStop);
        serial->setFlowControl(QSerialPort::NoFlowControl);
    
        if (serial->open(QIODevice::ReadWrite)) { 
            ui->connectAction->setEnabled(false);
            ui->disconnectAction->setEnabled(true);
            ui->settingsAction->setEnabled(false);
            showStatusMessage(tr("Connected to %1 : OK")
                              .arg(p.name));
        } else { 
            QMessageBox::critical(this, tr("Error"), serial->errorString());
    
            showStatusMessage(tr("Open error"));
        }
    }
    

    Someone have good idea how open more ports.
    I would be grateful for help.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Only one solution: have as many QSerialPort objects.

    Using e.g. a QVector<QSerialPort*> as member variable to keep them easily manageable.



  • Hi @erytcg

    To open more than one serialport

    you have two create more than one instance of QSerialPort:

    For example you have two serial ports on your device : (ttyUSB0, ttyUSB1)

    To open these ports you have to do something like this:

    QSerialPort* firstSerialPort = new QSerialPort();
    QSerialPort* secondSerialPort = new QSerialPort();
    
    firstSerialPort->setPortName("ttyUSB0");
    secondSerialPort->setPortName("ttyUSB1");
    .
    .
    .
    if (firstSerialPort->open(QIODevice::ReadWrite))
    .
    .
    .
    if (secondSerialPort->open(QIODevice::ReadWrite))
    .
    .
    .
    

    I hope this can help you



  • @mostefa I think it's not good idea i don't know how many devices I have to connect
    @SGaist can yoiu show me example how add add object to QVector and obtain acces to serialport name



  • @erytcg said in How to open more than once SerialPort:

    @mostefa I think it's not good idea i don't know how many devices I have to connect

    Then what about ?

    QVector<QSerialPort *> v;
        Q_FOREACH(QSerialPortInfo port, QSerialPortInfo::availablePorts()) {
            QSerialPort* serialPort = new QSerialPort() ;
    
    //Here set port informations
            serialPort->setPort(port);
    .
    .
    .
    
             if (serialPort->open(QIODevice::ReadWrite))
    {
    .
    .
                  v.append(serialPort);
    }
      }
    


  • void MainWindow::openSerialPort()
    {         
        QVector<QSerialPort *> v;
            Q_FOREACH(QSerialPortInfo port, QSerialPortInfo::availablePorts())
            {
               QSerialPort* serialPort = new QSerialPort();
               serialPort->setPort(port);
               serialPort->setBaudRate(QSerialPort::Baud9600);
               serialPort->setDataBits(QSerialPort::Data8);
               serialPort->setParity(QSerialPort::NoParity);
               serialPort->setStopBits(QSerialPort::OneStop);
               serialPort->setFlowControl(QSerialPort::NoFlowControl);
    
                if (serialPort->open(QIODevice::ReadWrite)) {
                     v.append(serialPort);
                     ui->listWidget->addItem(p.name);
                  
                } else { 
                    QMessageBox::critical(this, tr("Error"), serialPort->errorString());
    
                    showStatusMessage(tr("Open error"));
                }
            }
    
    }
    
    void MainWindow::closeSerialPort()
    {
        if (serialPort->isOpen())
        {
            serialPort->close();
            QList<QListWidgetItem*> items = ui->listWidget->selectedItems();
            foreach(QListWidgetItem * item, items)
            {
                delete ui->listWidget->takeItem(ui->listWidget->row(item));
            }
        }
    
        showStatusMessage(tr("Disconnected"));
    }
    

    it's ok?


  • Qt Champions 2016

    Hi
    In void MainWindow::closeSerialPort()
    you call if (serialPort->isOpen())

    But that is only serialPort pointer. you are not using the
    Vector<QSerialPort *> v; at all so i wonder if this is what u want ?

    I imagine you need to loop over v and close all and not just whatever
    serialPort points to ?



  • I don't understand good with this QVector. I don't know how acces to one of port and close one port not all.


  • Qt Champions 2016

    @erytcg
    Hi
    its a list of comports.

    so v[index] gives a QSerialPort *

    But you will have to answer what app does.

    Currently you open all comports available on device.

    Should closeSerialPort() close them all again?

    to close one you would do
    QSerialPort * Cur=v[0];
    Cur->close();
    or even
    v[0]->close();

    Notice i use 0 for closing the first.

    So to help you , i need to understand what app does as its uncommon to open ALL comports :)



  • So I need more functions, one for add aviable ports to vector and one to open specific port? For close functions I want close only one port.


  • Qt Champions 2016

    @erytcg

    • close functions I want close only one port.

    But which one?



  • Choosing from:
    QList<QListWidgetItem*> items = ui->listWidget->selectedItems();
    foreach(QListWidgetItem * item, items)
    {
    delete ui->listWidget->takeItem(ui->listWidget->row(item));
    }


  • Qt Champions 2016

    Hi
    if you move
    QVector<QSerialPort *> v;
    to the MainWindow.h (in the class)
    and remove serialPort variable also!

    then you could do

    void MainWindow::closeSerialPort( int index)
    {
    QSerialPort * serialPort = v[index];
    if (serialPort->isOpen())
    {
    serialPort->close();
    ..

    and close the one u want with
    closeSerialPort( some number)


  • Qt Champions 2016

    Oh u posted while i was writing

    Can you use the row index directly to the V list ?



  • yes I want to add opened COMports to ListWidget and close selected ports


  • Qt Champions 2016

    @erytcg

    If there is a 1 to 1 to the V list ( please rename to comports or something :)

    Then you can just use the
    void MainWindow::closeSerialPort( int index)
    {
    QSerialPort * serialPort = v[index];
    ...

    and call it from
    foreach(QListWidgetItem * item, items) {
    int index= ui->listWidget->row(item); //
    closeSerialPort( index);



  • Hey can you look at code? Now it's ok? :)

    void MainWindow::addAvailableSerialPorts()
    {
        QVector<QSerialPort *> v;
        Q_FOREACH(QSerialPortInfo port, QSerialPortInfo::availablePorts())
            {
               QSerialPort* serialPort = new QSerialPort();
               serialPort->setPort(port);
               serialPort->setBaudRate(QSerialPort::Baud9600);
               serialPort->setDataBits(QSerialPort::Data8);
               serialPort->setParity(QSerialPort::NoParity);
               serialPort->setStopBits(QSerialPort::OneStop);
               serialPort->setFlowControl(QSerialPort::NoFlowControl);
               v.append(serialPort);
            }
    }
    void MainWindow::openSerialPort(int index)
    {         
        QSerialPort * serialPort = v[index];
        if (serialPort->open(QIODevice::ReadWrite)) 
         {
             showStatusMessage(tr("Connected to %1 : OK").arg(p.name));
         } 
        else 
        {
             QMessageBox::critical(this, tr("Error"), serialPort->errorString());
             showStatusMessage(tr("Open error"));
        }
    }
    

  • Qt Champions 2016

    @erytcg said in How to open more than once SerialPort:

    Almost but one fatal error !

    void MainWindow::addAvailableSerialPorts()
    {
    QVector<QSerialPort *> v; <<<< This is a local var. It should be in class. windows .h. should not be defined here. only used.

    So in
    void MainWindow::openSerialPort(int index)
    {
    QSerialPort * serialPort = v[index]; <<< what v is this . it cannot be the one from addAvailableSerialPorts as that was local.



  • ok I add *QVector<QSerialPort > v; to private: mainwindow.h
    I have problem with close function port chooseing from list widget


  • Qt Champions 2016

    @erytcg

    you need to use the row int as index

    foreach(QListWidgetItem * item, items) {
    int index= ui->listWidget->row(item); //
    closeSerialPort( index);
    


  • Hey it's good idea to recall to function

    void MainWindow::on_connectAction_clicked()
    {
        openSerialPort(ui->serialPortInfoListBox->currentIndex());
    }
    

    I think it's not MVC


  • Qt Champions 2016

    @erytcg
    Hi
    Im not sure what you talk about.
    MVC= model, view , controller?

    Is there a question ?

    What you mean recall ?
    Do you open it in addAvailableSerialPorts ?



  • Yes I talk about model, view , controller.
    I add all avaibleports to vector in addAvailableSerialPorts ()
    i open in openSerialPort(int index) / index=QComboBox->currentIndex();
    and close in closeSerialPort(int index) / index=QListWidget->currentRow()+1;

    and all works fine I think, but if I want show received data on QCustomPlot widget.
    I don't know how to convert QByteArray to QVector<double>.
    My received data from qDebug() - "\x0B"
    Thanks a lot for help :)


  • Qt Champions 2016

    @erytcg
    Nope a list of Class * is not really MVC.

    Do you really need to convert QByteArray to QVector<double> ?
    Why not convert to doubles when you read and add directly to QVector instead?

    Also who sends the doubles? Its not trivial to send doubles over serial as they dont map
    nicely to chars and there can be a difference in byteorder and precision loss.



  • I need convert because QCustomPlot func need doubles

    void 	addData (const QVector< double > &keys, const QVector< double > &values, bool alreadySorted=false)
    or
    void 	addData (double key, double value)
    

  • Qt Champions 2016

    @erytcg
    Yes, i understand CustomPlot wants QVector<double> but i was wondering
    instead of storing all values in ByteArray and then convert, if it would be more easy
    to store directly in QVector when reading them off the serial port.

    Anyway, how do u know how many indexes one double will take in ByteArray ?
    double is normally 8 bytes (32 bit). Do you know the byte order from the sender?


  • Qt Champions 2016

    Hi
    You can test with this sample
    Uses QDataStream which should be good and fast.

    int main(int argc, char *argv[])
    {
    
    QByteArray byteArray;
    
    //generate ten random float value
    QVector<float> v;
    for (int i =0; i < 10;++i)
    {
    v << 100. * qrand()/RAND_MAX;
    }
    //ouput vector
    qDebug() << v;
    
    //write float value to array
    {
    QDataStream out (&byteArray,QIODevice::WriteOnly);
    foreach(float f,v)
    {
    out << f;
    }
    }
    
    //read all float from array
    QVector<float> v2;
    {
    QDataStream in(byteArray);
    while (!in.atEnd())
    {
    float f;
    in >> f;
    v2 << f;
    }
    }
    //ouput vector
    qDebug() << v2;
    
    return 0;
    }
    

    From here
    http://www.qtcentre.org/archive/index.php/t-24744.html



  • Maybe I try explain what should my applications do. I send to device command for example: LB - measure temperature and I receive
    AAAA, data is exchanged in ASCII format. Number is in Hex format. for example 0x075d. And I want add this received data to plot. And set interval between measurement.


  • Moderators

    @erytcg You get double numbers as hex?! Is the double format used by this device clearly specified? I mean, you need to know how to convert those hex strings to doubles for that you need to know the format and byte order.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.