Qtserialport bypass writebuffer and write notifications
-
Hello every one,
I'm trying to implemente dmx512 in my app with the help of qtserialport. it is a serial protocole based on timming to control light equipements.
The protocole is simple, i need to send continusly a break of 120 microseconde, a breakoff of 8 microseconde, a start byte and 512 byte of data 8N2, and wait until the next break. It run at 250000 bauds.
Qtserialport seems to accepte 250000 bauds.
here is a exemple of code in a Qthread because i need to write on the port continusly.
@void myQthread::run()
{
mutex.lock();
QByteArray dmxbyte(m_universe); //get the data contains in the QByteArray m_universe //containing the start dmx code and the 512 value and coping it in a new variable
dmxbyte[0]=0x00; //dmx star code to be sure
m_running = true;
mutex.unlock();QSerialPort monserialport; //create the serialport monserialport.setPortName(m_name);// set the port name if (monserialport.isOpen() == false) { if((monserialport.open(QIODevice::WriteOnly ))==false) { qWarning() << "Unable to open"; } if((monserialport.setBaudRate(250000,QSerialPort::AllDirections))==false) {qWarning() << "Unable to set 250kbps baudrate"; } qDebug()<<"baufrate :"<<monserialport.baudRate(); // to check that 250000 is return if( (monserialport.setDataBits(QSerialPort::Data8))==false) { qWarning() << "Unable to set 8N2 serial properties"; } if((monserialport.setFlowControl(QSerialPort::NoFlowControl))==false) { qWarning() << "Unable to set 8N2 serial properties"; } if((monserialport.setParity(QSerialPort::NoParity))==false) { qWarning() << "Unable to set 8N2 serial properties"; } if( (monserialport.setStopBits(QSerialPort::TwoStop))==false) { qWarning() << "Unable to set 8N2 serial properties"; } if( (monserialport.setDataErrorPolicy(QSerialPort::PassZeroPolicy))==false) { qWarning() << "Unable to set data error policy"; } if (isRunning() == false) start(); } while (m_running == true) { qint64 bw = 0; //bytes really writen bool isflush=0; QTime time; // start a timer to see the delay between two frame if (monserialport.isOpen() == false) { qDebug()<<"serial is not open"; goto endaction; } if(monserialport.setBreakEnabled(true)==false) { qWarning() << "Unable to toggle BREAK_ON"; goto framesleep; } usleep(120); if(monserialport.setBreakEnabled(false)==false) { qWarning() << "Unable to toggle BREAK_OFF"; goto framesleep; }
usleep(8);
time.start();
bw =monserialport.write(( char*) dmxbyte.data(),
dmxbyte.size());//or bw = monserialport.write(dmxbyte);
isflush=monserialport.flush();
qDebug()<<time.elapsed(); // to see how many time it take to write the data on the serialport
if(bw<513)
{
qWarning() << "Unable to write DMX data";
}mutex.lock();
dmxbyte=m_universe;
mutex.unlock();framesleep:
usleep(22754); // time to the next break
}endaction:
monserialport.close();
qDebug()<<"close serial";if(monserialport.isOpen()) { qWarning() << "Unable to close"; }
}
@My probleme is the folowing. I see i get 563 miliseconde for writing timing. I have a quick look on the qtseriaport architecture and i see that the write() fonction write data to a buffer and call after writenotifications to start writing on the port. I am on a ftdi usbtoserial converter.
I ask if there is a way to write directly to the port and bypass the buffer like the writeToPort() fonction.
thanks for all.
-
QtSerialPort was developed as the universal decision for the general circle of tasks with asynchronous streaming processing. It isn't intended for implementation of the "specific" protocols tied on strict timings, especially as used OS aren't able to provide these timings. In your case it is simpler to execute implementation of your protocol on the separate HW device (e.g. AVR, ARM and etc.) which would allow accurately and to trace clearly timings with high precision.
On the question I will tell that it is impossible to bypass the internal buffer and this action is no need, because it doesn't influence on anything. Because writing to the internal buffer it is nanoseconds time.
-
thanks for your reply kuzulis.
Dmx 512 is asynchronous stream.
unfortunately i can't use separate device, for my purpose. I do this way with other devices and it's work well, but in fact i try to use a specific popular device (open dmx from enttec) who is just a fttdi chip plug into a max485).
It work well with the ftd2xx drivers but there are not compatible with the ftdi VCP drivers that arduino and qtserial use on OSX.
The idea to bypass the writebuffer wasn't good, i try it and i get a QSerialPort::ResourceError.Do you know why it takes so much time (500 ms) to write a 512 buffer on the port?
So i think i am in a dead end.
Thanks for all.
-
bq. Do you know why it takes so much time (500 ms) to write a 512 buffer on the port?
No, I don't know why. Probably reason in tcdrain() ioctl through which the flush() method is implemented, maybe the notifiers is enabled so slow ... maybe something other...
You can try to leave from a separate thread and synchronous I/O, just using async approach.
Where instead of using flush() method, try to connect to signal bytesWtitten(qint64) to calculate number of bytes really written to port.Though if to be honest, it is necessary to test in a debugger or a profiler the reason of such slow data transmission.