2017-05-20 66 views
0

我已經創建了一個圍繞QSerialPort的包裝庫。我想與我的設備進行通信。首先,我發送list命令到我的設備,它應該返回該設備支持的命令列表。然而,在調試我的代碼時,我觀察到list命令正在發送到設備並且設備返回正確的響應(我使用串行流量嗅探器Linux工具進行調試)。但是,我沒有收到我的設備使用QSerialPort(當串行流量嗅探器工具被禁用時)的任何響應。經過幾次測試後,我無法完成工作。使用QSerialPort無法讀取任何東西

我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; 
}; 

我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; 
} 

而且我的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

「無法讀取任何使用QSerialPort」不是一個問題,它是一個聲明。你在結尾附加一個問號並不是一個問題。這是一個非常沒有理智的美國主義,讓我看到來自世界其他地區的人使用它。 –

+1

@MikeNakis:我已經編輯過標題。 – abhiarora

+0

你似乎沒有對'QSerialPort'本身做任何錯誤檢查 - 你應該連接到可用的各種信號來檢查發生了什麼。還要注意,在你的'Serial'構造函數中,如果'_p_port-> open'失敗,你會在刪除'_p_port'之前立即拋出異常。 –

回答

1

你幾乎錯過了需要的一切這個代碼工作:事件循環。現實生活中的I/O是異步的。當數據可用時,您不能僅通過端口進行「讀取」,而是實際讓異步I/O請求得到處理。是的,有一些傳統的API可以讓你做到這一點,但他們通常會導致意大利麪代碼,浪費的線程和糟糕的性能。

while (serial.available() == 0)循環是無操作的。它沒有做任何事情讓available()返回任何其他值。 available()在內部的所有內容都是讀取類的整數成員。你永遠不會運行任何可以更新存儲在該成員中的值的代碼。即使你將這個轉換爲serial.waitForReadyRead()確實更新了可用字節數,但你仍然沒有旋轉事件循環,因此你將無法處理超時或對應用程序中的任何其他事件作出反應可能需要做出反應。 QIODevice::waitForReadyRead只是爲了做一件事:當readyRead信號觸發時返回。它不會處理任何其他事件,並且它是用於移植阻止代碼的柺杖,並非真正用於生產用途。

你應該重新設計你的代碼是異步的,並由來自QSerialPort的信號驅動。這項工作將在QCoreApplication::exec之內完成 - 您不會擁有自己的循環。這種控制反轉對於異步I/O的工作是至關重要的。

參見例如this answer爲一個非常簡單的異步方法示例,this answer爲更完整的一個。