2017-05-20 1 views
0

Ich habe eine Wrapper-Bibliothek um QSerialPort erstellt. Ich möchte mit meinem Gerät kommunizieren. Zuerst sende ich den Befehl list an mein Gerät und es sollte eine Liste der von diesem Gerät unterstützten Befehle zurückgeben. Beim Debuggen meines Codes habe ich jedoch beobachtet, dass der Befehl list an das Gerät gesendet wird und das Gerät die entsprechende Antwort zurückgibt (ich habe mit seriellen Sniffer-Linux-Tools debuggt). Ich bekomme jedoch keine Antwort von meinem Gerät mit QSerialPort (während serielle Traffic-Sniffer-Tool deaktiviert war). Ich kann es nicht funktionieren, nachdem ich es mehrmals getestet habe.Kann nichts mit QSerialPort lesen

Mein serial.h:

class Serial : public Print { 

public: 
    Serial(); 
    explicit Serial(const char *dev_path); 
    ~Serial(); 

    int begin(unsigned long baudrate); 
    int begin(unsigned long baudrate, uint8_t cfg); 
    void end(void); 

    int available(void) const; 
    bool availableForWrite(void) const; 
    void flush(void); 
    bool isError(void) const; 
    void reset(void); 

    unsigned long write(uint8_t c); 
    unsigned long write(uint8_t *p_data, unsigned long maxSize); 
    int read(void); 

    void close(); 

    QSerialPort &getPort() 
    { 
     return *_p_port; 
    } 

public slots: 
    void readyBe(void); 

private: 
    QSerialPort *_p_port; 
    unsigned long _baudrate; 
}; 

Mein Serial.cpp:

Serial::Serial() 
{ 
    _p_port = new QSerialPort(); 
    if (_p_port == nullptr) 
     throw std::runtime_error("Can't allocate memory"); 
} 

Serial::Serial(const char *dev_path) 
{ 
    _p_port = new QSerialPort(QString(dev_path), QApplication::instance()); 
    if (_p_port == nullptr) 
     throw std::runtime_error("Can't allocate memory"); 
    // _p_port->setPortName(QString(dev_path)); 
    if (_p_port->open(QIODevice::ReadWrite) == false) { 
     throw std::runtime_error("Can't open the serial _p_port"); 
     delete _p_port; 
    } 
    _p_port->setBaudRate(QSerialPort::Baud9600); 
    _p_port->setDataBits(QSerialPort::Data8); 
    _p_port->setParity(QSerialPort::NoParity); 
    _p_port->setStopBits(QSerialPort::OneStop); 
    _p_port->setFlowControl(QSerialPort::NoFlowControl); 
} 

Serial::~Serial() 
{ 
    if (_p_port != nullptr) { 
     end(); 
     delete _p_port; 
    } 
} 

int Serial::begin(unsigned long baudrate) 
{ 
    if (_p_port->setBaudRate(baudrate, QSerialPort::AllDirections) == false) 
     return -1; 
    _baudrate = baudrate; 
    return 0; 
} 

void Serial::end() 
{ 
    if (_p_port->isOpen()) 
     _p_port->close(); 
} 

int Serial::available(void) const 
{ 
    int num_bytes = _p_port->bytesAvailable(); 
    return num_bytes; 
} 

bool Serial::availableForWrite(void) const 
{ 
    if (_p_port->isWritable()) 
     return true; 
    return false; 
} 

void Serial::flush() 
{ 
    _p_port->flush(); 
} 

unsigned long Serial::write(uint8_t c) 
{ 
    if (_p_port->putChar(c)) 
     return 1; 
    return 0; 
} 

unsigned long Serial::write(uint8_t *p_data, unsigned long maxSize) 
{ 
    return _p_port->write(reinterpret_cast<const char *>(p_data), (qint64)maxSize); 
} 

int Serial::read(void) 
{ 
    char c; 
    _p_port->getChar(&c); 
    return c; 
} 

void Serial::reset(void) 
{ 
    _p_port->clear(QSerialPort::AllDirections); 
    _p_port->clearError(); 
} 

bool Serial::isError(void) const 
{ 
    if (_p_port->error() == QSerialPort::NoError) 
     return false; 
    return true; 
} 

Und mein main.cpp:

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    MainWindow w; 
    // w.show(); 

    Serial serial("ttyACM0"); 
    if (serial.begin(115200)) 
     std::cout << "Failed to set Baud rate" << std::endl; 
    std::cout << "Sending data" << std::endl; 
    // QObject::connect(&(serial.getPort()), SIGNAL(readyRead()), &serial, SLOT(readyBe())); 
    serial.print("list\r"); 
    serial.flush(); 

    while (true) { 
     while (true) { 
      while (serial.available() == 0) { 
       if (serial.isError()) { 
        std::cout << "Error" << std::endl; 
        // serial.reset(); 
       } 
      } 

      char c = serial.read(); 
      std::cout << c; 
      if (c == '\n') 
       break; 
     } 
     std::cout << std::endl; 
    } 

    return a.exec(); 

} 
+0

"Kann nichts mit QSerialPort lesen" ist keine Frage, es ist eine Aussage. Die Tatsache, dass Sie am Ende ein Fragezeichen angehängt haben, macht das nicht zu einer Frage. Es ist ein sehr unintellektueller Amerikanismus, und es macht mich traurig zu sehen, dass Menschen aus anderen Teilen der Welt es benutzen. –

+1

@MikeNakis: Ich habe den Titel bearbeitet. – abhiarora

+0

Sie scheinen keine Fehlerüberprüfung am 'QSerialPort' selbst vorzunehmen - Sie sollten sich mit den verschiedenen verfügbaren Signalen verbinden, um zu überprüfen, was passiert. Beachten Sie auch, dass Sie in Ihrem 'Serial'-Konstruktor, wenn' _p_port-> open' fehlschlägt, eine Ausnahme sofort auslösen *, bevor Sie '_p_port' löschen. –

Antwort

1

Sie haben so ziemlich alles verpasst, die für Dieser Code funktioniert: die Ereignisschleife. I/O im realen Leben ist asynchron. Sie können nicht einfach nur vom Port "lesen", ohne dass Sie sich informieren lassen, wenn die Daten verfügbar sind, und die asynchronen E/A-Anforderungen tatsächlich verarbeiten zu lassen. Ja, es gibt einige Legacy-APIs, mit denen Sie das tun können, die aber meistens zu Spaghetti-Code, verschwendeten Threads und schlechter Leistung führen.

Die while (serial.available() == 0) Schleife ist ein No-Op. Es tut nichts, um den available() anderen Wert tatsächlich zurückgeben zu lassen. All das available() liest intern ein Integer-Member einer Klasse. Sie führen keinen Code aus, der den in diesem Element gespeicherten Wert aktualisieren könnte. Selbst wenn Sie dies in serial.waitForReadyRead() konvertieren würde, die macht aktualisieren Sie die Anzahl der verfügbaren Bytes, Sie sind immer noch nicht drehen eine Ereignisschleife, und Sie werden daher nicht in der Lage sein, Timeouts zu verarbeiten oder auf andere Ereignisse einer Anwendung reagieren Vielleicht muss man darauf reagieren. QIODevice::waitForReadyRead soll nur eins tun: zurückgeben, wenn ein readyRead Signal feuern würde. Es wird keine anderen Ereignisse verarbeiten, und es ist eine Krücke, die verwendet wird, um blockierenden Code zu portieren, und ist nicht wirklich für den produktiven Einsatz gedacht.

Sie sollten Ihren Code so umformen, dass er asynchron und von Signalen von QSerialPort gesteuert wird. Die Arbeit wird dann innerhalb von QCoreApplication::exec erledigt - Sie werden keine eigene Schleife haben. Diese Inversion der Steuerung ist entscheidend für das Arbeiten mit asynchronen E/A.

Siehe z.B. this answer für ein sehr einfaches Beispiel eines asynchronen Ansatzes und this answer für einen vollständigeren.

Verwandte Themen