Article View: pl.comp.os.linux.programowanie
Article #72841Czekanie na wolny bufor portu szeregowego - co robię źle?!?
From: spryciarzsprytny7
Date: Thu, 05 Jul 2018 08:11
Date: Thu, 05 Jul 2018 08:11
185 lines
8676 bytes
8676 bytes
Witam
Piszę obsługę portu szeregowego w C++ z użyciem Linux Api. 2 obiekty klasy PortSzeregowy mają równolegle zapisywać i odczytywać ten port. Odczyt i zapis generalnie działa. Jednak chcę zapewnić działanie tej kasy (PortSzeregowy) w warunkach ekstremalnych (pod dużym obciążeniem). Dlatego nie robię tej komunikacji na timerach tylko na blokadzie pselect. Ta blokada działa w przypadku odczytu z portu, jednak analogiczny kod nie działa w przypadku zapisu.
Po prostu pselect (funkcja SerialPort::send()) nie zatrzymuje się w momencie gdy bufor wyjściowy portu jest pełen (gdy jest wywoływana przed odczytem). Poniżej zamieszczam funkcje zapisu i odczytu z portu szeregowego. Jeśli to możliwe to proszę o pomoc w zdiagnozowaniu powodu nie zatrzymywania się pselect (funkcja SerialPort::send()) w przypadku gdy bufor wyjściowy portu szeregowego jest pełen.
z góry dzięki i pozdro
Jacek
void SerialPort::receive()
{
// http://www.linuxprogrammingblog.com/code-examples/using-pselect-to-avoid-a-signal-race
// https://www.cmrr.umn.edu/~strupp/serial.html
if(mPortDescriptor < 0)
throw Exception(tr("Zły deskryptor pliku: %1").arg(mPortDescriptor).toUtf8().data());
struct sigaction lSigAction;
memset (&lSigAction, 0, sizeof(lSigAction));
lSigAction.sa_handler = gSignTermHandler;
// This server should shut down on SIGTERM.
if(sigaction(SIGTERM, &lSigAction, 0))
throw Exception(tr("Błąd sigaction! %1, %2").arg(errno).arg(strerror(errno)));
sigset_t lMask;
sigemptyset (&lMask);
sigaddset (&lMask, SIGTERM);
sigset_t orig_mask;
if(sigprocmask(SIG_BLOCK, &lMask, &orig_mask) < 0)
throw Exception(tr("Błąd sigprocmask! %1, %2").arg(errno).arg(strerror(errno)));
struct timespec timeout;
timeout.tv_sec = 1;
timeout.tv_nsec = 0;
fd_set lFileDescriptorSet;
/* BANG! we can get SIGTERM at this point, but it will be
* delivered while we are in pselect(), because now
* we block SIGTERM.
*/
FD_ZERO(&lFileDescriptorSet);
FD_SET(mPortDescriptor, &lFileDescriptorSet);
while(true)
{
int lRes = pselect(mPortDescriptor + 1, &lFileDescriptorSet, NULL, NULL, &timeout, &orig_mask);
if(mEnd)
return;
if((lRes < 0) && (errno != EINTR))
throw Exception(tr("Bład pselect! %1, %2").arg(errno).arg(strerror(errno)));
if(lRes == 0) // timeout
continue;
if(gExitRequest)
throw Exception(tr("Przechwycono sygnał SIGTERM! Koniec odbierania danych."));
if(!FD_ISSET(mPortDescriptor, &lFileDescriptorSet))
continue;
int lSize = 0;
ioctl(mPortDescriptor, FIONREAD, &lSize);
if(lSize <= 0)
continue;
QByteArray lResult;
lResult.resize(lSize);
int lReaded(0), lPartial(0);
while(lReaded < lSize)
{
if(mEnd)
return;
lPartial = ::read(mPortDescriptor, lResult.data(), lSize);
if(lPartial > 0)
lReaded += lPartial;
else if(lPartial < 0)
{
qCritical() << tr("Uwaga! Błąd czytania portu szeregowego! Kod błędu: %1, wiadomość: %2").arg(errno).arg(strerror(errno));
break;
}
}
emit read(lResult);
}
}
void SerialPort::send()
{
// http://www.linuxprogrammingblog.com/code-examples/using-pselect-to-avoid-a-signal-race
// https://www.cmrr.umn.edu/~strupp/serial.html
if(mPortDescriptor < 0)
throw Exception(tr("Zły deskryptor pliku: %1").arg(mPortDescriptor).toUtf8().data());
struct sigaction lSigAction;
memset (&lSigAction, 0, sizeof(lSigAction));
lSigAction.sa_handler = gSignTermHandler;
// This server should shut down on SIGTERM.
if(sigaction(SIGTERM, &lSigAction, 0))
throw Exception(tr("Błąd sigaction! %1, %2").arg(errno).arg(strerror(errno)));
sigset_t lMask;
sigemptyset(&lMask);
sigaddset(&lMask, SIGTERM);
sigset_t orig_mask;
if(sigprocmask(SIG_BLOCK, &lMask, &orig_mask) < 0)
throw Exception(tr("Błąd sigprocmask! %1, %2").arg(errno).arg(strerror(errno)));
struct timespec timeout;
timeout.tv_sec = 1;
timeout.tv_nsec = 0;
fd_set lFileDescriptorSet;
/* BANG! we can get SIGTERM at this point, but it will be
* delivered while we are in pselect(), because now
* we block SIGTERM.
*/
FD_ZERO(&lFileDescriptorSet);
FD_SET(mPortDescriptor, &lFileDescriptorSet);
int lNumberToAquire(0);
while(true)
{
lNumberToAquire = 0;
if(mBufferEnd > mBufferStart)
lNumberToAquire = mBufferEnd - mBufferStart;
else if(mBufferEnd < mBufferStart)
lNumberToAquire = mSendBuffer.size() - mBufferStart;
if(lNumberToAquire <= 0)
lNumberToAquire = 1;
int lFreeSpaceSize = 0;
ioctl(mPortDescriptor, TIOCOUTQ, &lFreeSpaceSize);
if(lFreeSpaceSize <= 0) // we must wait for serial port
{
int lRes = pselect(mPortDescriptor + 1, NULL, &lFileDescriptorSet, NULL, &timeout, &orig_mask);
if(mEnd)
return;
if((lRes < 0) && (errno != EINTR))
throw Exception(tr("Bład pselect! Kod błedu: %1, komunikat: %2").arg(errno).arg(strerror(errno)));
if(lRes == 0) // timeout
continue;
if(gExitRequest)
throw Exception(tr("Przechwycono sygnał SIGTERM! Koniec wysyłania danych."));
if(!FD_ISSET(mPortDescriptor, &lFileDescriptorSet))
continue;
}
ioctl(mPortDescriptor, TIOCOUTQ, &lFreeSpaceSize);
if(lFreeSpaceSize <= 0)
{
qWarning() << tr("%1 Uwaga: Brak miejsca w bufoerze wyjściowym portu szeregowego!").arg(QTime::currentTime().toString("hh:mm:ss.z"));
continue;
}
lNumberToAquire = qMin(lNumberToAquire, lFreeSpaceSize);
//#ifdef DEBUG
// int lSemaphore(mAvailableData.available());
//#endif
if((lNumberToAquire > 0) && mAvailableData.tryAcquire(lNumberToAquire, 1000))
{
//#ifdef DEBUG
// int lSemaphore2(mAvailableData.available());
//#endif
int lWriten(0), lPartial(0);
while(lWriten < lNumberToAquire)
{
lPartial = ::write(mPortDescriptor, mSendBuffer.data() + mBufferStart, lNumberToAquire);
if(lPartial > 0)
lWriten += lPartial;
else if(lPartial < 0)
{
qCritical() << tr("Błąd zapisu do portu szeregowego!!! Kod błędu: %1, Wiadomość błędu: %2").arg(errno).arg(strerror(errno));
break;
}
}
// qDebug() << QTime::currentTime().toString("hh:mm:ss.z") << "Write to the serial port.";
mBufferStart = (mBufferStart + lNumberToAquire) % mSendBufferSize;
mFreeSpace.release(lNumberToAquire);
}
if(mEnd)
return;
}
}
Technical Details
Message-ID:
<691200d3-8311-4c65-a7a5-f3f0820760c6@googlegroups.com>Path:
mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.icm.edu.pl!news.nask.pl!news.nask.org.pl!news.unit0.net!weretis.net!feeder6.news.weretis.net!feeder.usenetexpress.com!feeder-in1.iad1.usenetexpress.com!border1.nntp.dca1.giganews.com!nntp.giganews.com!f6-v6no218472qth.0!news-out.google.com!u13-v6ni396qtg.0!nntp.google.com!f6-v6no218462qth.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mailShow Full Headers
Complete Article Headers
X-Received: by 2002:a37:9406:: with SMTP id w6-v6mr2930869qkd.25.1530778286206; Thu, 05 Jul 2018 01:11:26 -0700 (PDT) X-Received: by 2002:a0c:be8a:: with SMTP id n10-v6mr422583qvi.6.1530778285936; Thu, 05 Jul 2018 01:11:25 -0700 (PDT) Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.icm.edu.pl!news.nask.pl!news.nask.org.pl!news.unit0.net!weretis.net!feeder6.news.weretis.net!feeder.usenetexpress.com!feeder-in1.iad1.usenetexpress.com!border1.nntp.dca1.giganews.com!nntp.giganews.com!f6-v6no218472qth.0!news-out.google.com!u13-v6ni396qtg.0!nntp.google.com!f6-v6no218462qth.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail Newsgroups: pl.comp.os.linux.programowanie Date: Thu, 5 Jul 2018 01:11:25 -0700 (PDT) Complaints-To: groups-abuse@google.com Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=5.226.117.166; posting-account=gLUTRAoAAADr4_ywPlZaMoP-wsVeFJh_ NNTP-Posting-Host: 5.226.117.166 User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: <691200d3-8311-4c65-a7a5-f3f0820760c6@googlegroups.com> Subject: Czekanie na wolny bufor portu szeregowego - co robię źle?!? From: spryciarzsprytny7@gmail.com Injection-Date: Thu, 05 Jul 2018 08:11:26 +0000 Lines: 220 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit