PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Segfault beim Ansprechen der seriellen Schnittstelle



axeljaeger
16-10-2003, 14:23
Ich muss demnächst ein Gerät über die serielle Schnittstelle ansteuern. Dazuhab ich hier im Board schon diverse Threads gefunden und sogar ein Beispielprogramm, das ich ganz gut benutzen konnte. Ich hab das Beispiel jetzt aufgedröselt und in eine Qt-App verpackt. Leider ergibt sich das Problem, das ein Segfault auftaucht, den ich nicht nachvollziehen kann und GDB meldet auch nur, das er auf den Speicher an der Stelle 0xirgendwas nicht zugreifen kann. Der Segfault soll in der Methode QObject::recievers(const char*) auftritt, und zwar immer dann, wenn ich die Methode closePort aufrufe. Ich nehme stark an, das es nicht an tim->stop() liegt, weil ich das vorher nicht drinn hatte und der Fehler trotzdem auftrat. Erschwerend kommt hinzu, das ich den Quelltext zwar nachvollziehen kann, aber zum Teil nicht verstehe, warum der Originalautor das so und nicht anders gemacht hat. Entsprechende Stellen habe ich gekennzeichnet. Vielleicht kann sich jmd. einene Reim drauf machen, warum das so gemacht wurde. Ich verstehe z.B. nicht, warum lowlevel-DateiIO verwendet wurde. Mit Highlevel-DateiIO könnte ich aus dem FILE* ein QFile machen und wär fein aus dem Schneider. Ich bedanke mich schonmal im Vorraus für jegliche Mühen, weil ich finde, es ist schon recht viel von mir verlangt. Zum Testen verwende ich im Moment ein HandGPS, das nur Ascii-Daten rausgibt und als Flowcontroll Software nimmt (Kabel hat nur drei Adern). Wie man an den verschiedensprachigen Kommentaren sieht, hat der Autor woll auch ganz gut mit der Zwischenablage gearbeitet.



#include <qvbox.h>
#include <qapplication.h>
#include <qtextedit.h>
#include <qtimer.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <qpushbutton.h>

class TerminalWidget : public QVBox
{
Q_OBJECT
public:
TerminalWidget(QWidget* parent = 0);
~TerminalWidget();

public slots:
void readComData();
void openPort();
void closePort();
private:
QTextEdit* out;
int fd;
QTimer* tim;
QPushButton* btnOpen, *btnClose;
QString outbuffer;
};

TerminalWidget::TerminalWidget(QWidget* parent) : QVBox(parent), fd(0)
{
out = new QTextEdit(this);
out->setTextFormat(LogText);

btnOpen = new QPushButton("Open Port", this);
btnClose = new QPushButton("Close Port", this);

connect(btnOpen, SIGNAL(clicked()), this, SLOT(openPort()));
connect(btnClose, SIGNAL(clicked()), this, SLOT(closePort()));

tim = new QTimer(this);
connect(tim, SIGNAL(timeout()), this, SLOT(readComData()));

}
TerminalWidget::~TerminalWidget()
{
closePort();
}
void TerminalWidget::openPort()
{
closePort() ;

fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0)
{
printf("FEHLER : Kann Port nicht Oeffnen : %d %s\n", errno, strerror(errno));
}
else
{
struct termios my_termios;
tcgetattr(fd, &my_termios);
tcflush(fd, TCIFLUSH);
/* Baudrate und BIT-Flags werden hier gesetzt */
my_termios.c_cflag = B4800 | CS8 |CREAD | CLOCAL | HUPCL | IXON | IXOFF;
cfsetospeed(&my_termios, B4800);
tcsetattr(fd, TCSANOW, &my_termios);
}
tim->start(10);
}

void TerminalWidget::closePort()
{
if (fd > 0)
{
tim->stop();
close(fd); // <-- Das ist wohl was ganz böses
}
}

void TerminalWidget::readComData()
{
int iIn;
char buffer[4096];
int iMax = 4096;
if (fd < 1)
{
printf("FEHLER : Kein Port offen \n");
return;
}

strncpy (buffer, "N/A", iMax < 4 ? iMax : 4); // <-- Wozu?

/* Hier werden die Daten vom Port eingelesen */
iIn = read(fd, buffer, 4095);

if (iIn < 0)
{
if (errno == EAGAIN)
return; // assume that command generated no response
else
printf("FEHLER : Lesefehler %d %s\n", errno, strerror(errno));
}
else
{
buffer[iIn<iMax?iIn:iMax] = '\0';
}
outbuffer.append(buffer);
out->setText(outbuffer);
}

#include "serial.moc.cpp"

int main(int argc, char ** argv)
{
QApplication app(argc, argv);
TerminalWidget tw;
app.setMainWidget(&tw);
tw.show();
return app.exec();
}

anda_skoa
16-10-2003, 16:39
fd ist nicht initialisiert.
Wenn du am Anfang von openPort() closePort() aufrufst und fd irgend ein Wert > 0 ist -> zack.

Btw: QSocketNotifier könnte statt dem Timer auch gehen.

Ciao,
_

axeljaeger
16-10-2003, 16:54
Neinnein, einmal kann man das schon machen, dann sehe ich auch den Output von dem GPS. Aber wenn ich dann zumache -> zack

QSocketNotifier würde ich gerne nutzen, das mit dem Timer finde ich auch höchst unelegant. Aber dazu müsste ich erstmal wissen, warum derjenige, der den Code geschrieben hat, lowlevel-fileio benutzt hat und nicht FILE*, aus dem man ja einfach ein QFile machen könnte. Vielleicht kann man auch erst die Portsettings setzen und die serielle schnittstelle dann direkt mit QFile öffnen?

anda_skoa
17-10-2003, 11:01
Original geschrieben von axeljaeger
Neinnein, einmal kann man das schon machen, dann sehe ich auch den Output von dem GPS. Aber wenn ich dann zumache -> zack

In dem Fall hast du am Anfang immer Glück.
Wäre schon besser, die Variable auf einen sicheren Wert zu setzen, auch nach dem Close.



Aber dazu müsste ich erstmal wissen, warum derjenige, der den Code geschrieben hat, lowlevel-fileio benutzt hat und nicht FILE*, aus dem man ja einfach ein QFile machen könnte.

Mit einem Filedescriptor kann man auch ein QFile aufmachen. QFile::open(int, int)



Vielleicht kann man auch erst die Portsettings setzen und die serielle schnittstelle dann direkt mit QFile öffnen?
Möglich, die Frage ist, wie man da feststellt, ob was im Lesepuffer is, bzw. ob der Sendepuffer bereit ist.
Vielleicht kann man ein QSocketDevice benutzen.

Hab zum Thema folgendes Posting in qt-interest gefunden:
http://qt-interest.trolltech.com/new/2002-02/thread00332-0.html

Ciao,
_

axeljaeger
17-10-2003, 11:20
Original geschrieben von anda_skoa
In dem Fall hast du am Anfang immer Glück.
Wäre schon besser, die Variable auf einen sicheren Wert zu setzen, auch nach dem Close.


Auf 0 setzen zum Beispiel?


Original geschrieben von anda_skoa

Mit einem Filedescriptor kann man auch ein QFile aufmachen. QFile::open(int, int)


Das werd ich probieren

Original geschrieben von anda_skoa

Möglich, die Frage ist, wie man da feststellt, ob was im Lesepuffer is, bzw. ob der Sendepuffer bereit ist.
Vielleicht kann man ein QSocketDevice benutzen.

Was ich heut noch alles probieren möcht...
Das werd ich probieren

Original geschrieben von anda_skoa

Hab zum Thema folgendes Posting in qt-interest gefunden:
http://qt-interest.trolltech.com/new/2002-02/thread00332-0.html


Das QExtSerial kenne ich, das kompiliert bei mir nicht und ich warte seit Mittwoch abend auf eine Mail vom Autor.

anda_skoa
17-10-2003, 11:26
Original geschrieben von axeljaeger
Auf 0 setzen zum Beispiel?

-1, 0 ist ein gültiger fd.



Das QExtSerial kenne ich, das kompiliert bei mir nicht und ich warte seit Mittwoch abend auf eine Mail vom Autor.

Eventuell hilft ein Blick in den Source von KDE Programmen, die Serial benutzen.
KPilot, Kandy, etc.

Ciao,
_

axeljaeger
17-10-2003, 16:14
Ic hab Post vom Autor von QExtSerial bekommen. Die Library kompiliert jetzt, ich hab sie aber noch nicht ausprobiert. QExtSerial stellt ein QIODevice zur Vefügung, genauso wie ein QFile auch ein QIODevice wäre. Deswegen glaube ich kaum, das ich um den Timer herumkommen werde.