驱动程序CH341 USB适配器串行端口或QSerialPort不适用于Linux

时间:2014-04-13 09:03:44

标签: linux qt linux-kernel qtserialport

以下代码在Windows中正常运行,但Linux不起作用。我使用相同的PC,两个操作系统都是原生安装的。我不使用虚拟机。我需要在Linux上工作。我已尝试过不同的Linux发行版,但无法在任何地方使用。

// In the main class:
QSerialPortInfo info = XXXX; // Generally in Linux: /dev/ttyUSB0, in win: COM1
QSerialPort serial;
QObject::connect(&serial, SIGNAL(readyRead()), this, SLOT(onReadyRead()), Qt::DirectConnection);
QObject::connect(&serial, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)), Qt::DirectConnection);
QObject::connect(&serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onError(QSerialPort::SerialPortError)), Qt::DirectConnection);

// Slot
void MyClass::onReadyRead()
{
    qDebug()<<"Signal onReadyRead";
    buffer_mutex.lock();
    buffer += serial.readAll();
    qDebug()<<"Read: "<<qstr_to_hexstr(buffer);
    bufferNotEmpty.wakeAll();
    buffer_mutex.unlock();
}

void MyClass::onError(QSerialPort::SerialPortError error) {
    qCritical()<<"Serial Port Error: "<<(int)error;
}

void MyClass::onBytesWritten(qint64 size){
    qDebug()<<"onBytesWritten: "<<size;
}


// In another place I did:
serial.setPort(info); 
if(!serial.open(QIODevice::ReadWrite))
    return false;

qDebug()<<"Init Setting!...";

if(!serial.setBaudRate(QSerialPort::Baud9600))
    qCritical()<<"Error in setBaudRate";
if(!serial.setDataBits(QSerialPort::Data8))
    qCritical()<<"Error in setDataBits";
if(!serial.setParity(QSerialPort::EvenParity))
    qCritical()<<"Error in setParity";
if(!serial.setStopBits(QSerialPort::OneStop))
    qCritical()<<"Error in setStopBits";
if(!serial.setFlowControl(QSerialPort::SoftwareControl))
    qCritical()<<"Error in setFlowControl";
if(!serial.setDataTerminalReady(true))
    qCritical()<<"Error in setDataTerminalReady";

qDebug()<<"Setting ready!...";

如果发送1个字节,则设备会响应并正确发送数据。

示例:

// In the main class:
const char enq[2] = {0x05, '\0'};
serial.write (enq);

// In onReadyRead:
serial.readAll(); // Works on Win / Linux

如果发送了超过1个字节的设备,则不响应linux中的请求。

示例:

// In the main class:
const char command[6] = {0x02, 'S', '1', 0x03, 'a', '\0'};
serial.write(command);

// In onReadyRead
serial.readAll(); // Works only in Win

此事件仅在Windows中触发。在Linux中,它永远不会工作,没有收到或以错误的格式到达,也从未识别过远程设备。

我的Windows登录:

{Debug}         Init Setting!... 
{Debug}         Setting ready!...
{Debug}         Write:  " 0x05 "
{Debug}         onBytesWritten:  1 
{Debug}         buffer wait!... 
{Debug}         Signal onReadyRead 
{Debug}         Read:  " 0x02 `@ 0x03 #" 
{Debug}         buffer size:  5 
{Critical}      Serial Port Error:  0 
{Debug}         Write:  " 0x02 S1 0x03 a" 
{Debug}         onBytesWritten:  5 
{Debug}         buffer wait!... 
{Debug}         Signal onReadyRead 
{Debug}         Read:  " 0x02 S100 0x0A 00000000000000000 0x0A 00000479" 
{Debug}         buffer size:  32 
{Debug}         buffer wait!... 
{Debug}         Signal onReadyRead 
{Debug}         Read:  " 0x02 S100 0x0A 00000000000000000 0x0A 00000479 0x0A 00000 0x0A 00000330 0x0A 00000 0x0A 0061 0x0A 0000 0x0A " 
{Debug}         buffer size:  64 
{Debug}         Signal onReadyRead 
{Debug}         buffer wait!... 
{Debug}         Read:  " 0x02 S100 0x0A 00000000000000000 0x0A 00000479 0x0A 00000 0x0A 00000330 0x0A 00000 0x0A 0061 0x0A 0000 0x0A X-XXXXXXXX 0x0A XXXXXXXXX 0x0A 221715 0x0A 120414 0x0A  0x03  0x1B " 
{Debug}         buffer size:  103 
{Critical}      Serial Port Error:  0 

(我用&#39; X&#39;字符替换设备的实际响应)

我的Linux登录:

{Debug}         Init Setting!... 
{Debug}         Setting ready!...
{Debug}         Write:  " 0x05 "
{Debug}         onBytesWritten:  1 
{Debug}         buffer wait!... 
{Debug}         Signal onReadyRead 
{Debug}         Read:  " 0x02 `@ 0x03 #" 
{Debug}         buffer size:  5 
{Critical}      Serial Port Error:  0 
{Debug}         Write:  " 0x02 S1 0x03 a" 
{Debug}         onBytesWritten:  5 
{Debug}         buffer wait!... 
{Debug}         buffer wait!... 
{Debug}         buffer wait!... 
{Debug}         buffer wait!... 
{Debug}         buffer wait!... 
{Debug}         buffer wait!... 
{Debug}         buffer wait!... 
{Debug}         buffer wait!... 
{Debug}         buffer wait!... 
{Debug}         buffer wait!... 
{Debug}         timeout!... (15 sec for timeout)

USB串行适配器:CH340

In Windows: USB\VID_1A86&PID_7523&REV_0254
In Linux:
    Apr 13 01:16:58 kali kernel: [47844.260136] usb 2-1: new full-speed USB device number 16 using uhci_hcd
    Apr 13 01:16:58 kali kernel: [47844.428098] usb 2-1: New USB device found, idVendor=1a86, idProduct=7523
    Apr 13 01:16:58 kali kernel: [47844.428115] usb 2-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
    Apr 13 01:16:58 kali kernel: [47844.428126] usb 2-1: Product: USB2.0-Ser!
    Apr 13 01:16:58 kali kernel: [47844.431268] ch341 2-1:1.0: ch341-uart converter detected
    Apr 13 01:16:58 kali kernel: [47844.445398] usb 2-1: ch341-uart converter now attached to ttyUSB0
    Apr 13 01:16:58 kali mtp-probe: checking bus 2, device 16: "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1"
    Apr 13 01:16:58 kali mtp-probe: bus: 2, device: 16 was not an MTP device

PD:对不起我的英语,尽量使用谷歌翻译:(...

更多信息1:

Apr 13 04:10:55 kali kernel: [ 4872.627980] tty ttyUSB0: serial_write - 1 byte(s)
Apr 13 04:10:55 kali kernel: [ 4872.629763] tty ttyUSB0: serial_chars_in_buffer
Apr 13 04:10:55 kali kernel: [ 4872.629778] tty ttyUSB0: serial_wait_until_sent
Apr 13 04:10:55 kali kernel: [ 4872.638252] tty ttyUSB0: serial_chars_in_buffer
Apr 13 04:10:55 kali kernel: [ 4872.638267] tty ttyUSB0: serial_write_room
Apr 13 04:10:55 kali kernel: [ 4872.638278] tty ttyUSB0: serial_chars_in_buffer
Apr 13 04:10:55 kali kernel: [ 4872.638287] tty ttyUSB0: serial_write_room
Apr 13 04:10:55 kali kernel: [ 4872.639438] tty ttyUSB0: serial_chars_in_buffer
Apr 13 04:10:55 kali kernel: [ 4872.639458] tty ttyUSB0: serial_write_room
Apr 13 04:10:55 kali kernel: [ 4872.639475] tty ttyUSB0: serial_chars_in_buffer
Apr 13 04:10:55 kali kernel: [ 4872.639488] tty ttyUSB0: serial_write_room
Apr 13 04:10:56 kali kernel: [ 4873.641799] tty ttyUSB0: serial_ioctl - cmd 0x540b
Apr 13 04:10:56 kali kernel: [ 4873.646884] tty ttyUSB0: serial_write - 5 byte(s)
Apr 13 04:10:56 kali kernel: [ 4873.647152] ch341-uart ttyUSB0: ch341_update_line_status - multiple status change
Apr 13 04:10:56 kali kernel: [ 4873.647176] ch341-uart ttyUSB0: ch341_update_line_status - delta=0x01
Apr 13 04:10:56 kali kernel: [ 4873.647384] tty ttyUSB0: serial_chars_in_buffer
Apr 13 04:10:56 kali kernel: [ 4873.647401] tty ttyUSB0: serial_wait_until_sent
Apr 13 04:10:56 kali kernel: [ 4873.649144] ch341-uart ttyUSB0: ch341_update_line_status - multiple status change
Apr 13 04:10:56 kali kernel: [ 4873.649166] ch341-uart ttyUSB0: ch341_update_line_status - delta=0x01
Apr 13 04:10:56 kali kernel: [ 4873.692152] ch341-uart ttyUSB0: ch341_update_line_status - multiple status change
Apr 13 04:10:56 kali kernel: [ 4873.692170] ch341-uart ttyUSB0: ch341_update_line_status - delta=0x01
Apr 13 04:10:56 kali kernel: [ 4873.694133] ch341-uart ttyUSB0: ch341_update_line_status - multiple status change
Apr 13 04:10:56 kali kernel: [ 4873.694148] ch341-uart ttyUSB0: ch341_update_line_status - delta=0x01

我重建ch341.c并添加:

if (!delta)
    return;

dev_info(&port->dev, "%s - delta=0x%02X\n", __func__, delta); // <---- New Line

if (delta & CH341_BIT_CTS)
    port->icount.cts++;
if (delta & CH341_BIT_DSR)
    port->icount.dsr++;
if (delta & CH341_BIT_RI)
    port->icount.rng++;
if (delta & CH341_BIT_DCD) {
    port->icount.dcd++;
    tty = tty_port_tty_get(&port->port);
    if (tty) {
        usb_serial_handle_dcd_change(port, tty,
                    status & CH341_BIT_DCD);
        tty_kref_put(tty);
    }
}

日志中的delta = 0x01是标志:

#define CH341_BIT_CTS 0x01

更多信息2:

在写/读的线程中我希望wakeAll,在onReadyRead上运行。如果在检查缓冲区是否为空之前传递第二个make readAll。例如:

// In the main class:
QWaitCondition bufferNotEmpty;

// In my function write/read:
serial.write(data, size);
buffer_mutex.lock();
while(time(NULL)-timeStart<timeoutWait && serial.isOpen()) {
    buffer += serial.readAll();
    if(buffer.count()>0){
        qDebug()<<"buffer size: "<<buffer.count();
        //Interprete the buffer here...

        if(bufferComplete) 
            break;
    }
    qDebug()<<"buffer wait!...";
    bufferNotEmpty.wait(&buffer_mutex, 1000);
}
buffer.clear();
buffer_mutex.unlock();

更多信息3:

我的内核是3.12.6,但是我从GitHub更新了这个文件并重建了这个驱动程序:

https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c https://github.com/torvalds/linux/blob/master/drivers/usb/serial/usb-serial.c (commit d9a38a8741fdffabc32e6d0943b1cdcf22712bec)

1 个答案:

答案 0 :(得分:7)

感谢Linux的开发人员,解决了我的问题,在maillist中没有实现奇偶校验的CH34x驱动程序是为将来有这个问题的人提供的链接PATCH,而不是它们是否适用于官方内核,现在只有这样是重建驱动程序。

http://marc.info/?l=linux-serial&m=139749273432052&w=2