Forum: Projekte & Code PortableSerialLib - Portable Serial Port Library


von Vlad T. (vlad_tepesch)


Lesenswert?

Hi,

Letztens hatte ich nach einer kleinen C-Lib gesucht, die die Ansteuerung 
der Seriellen Schnittstelle kapselt, so dass für Linux und Windows keine 
Codeanpassungen notwendig sind.

Da die Suchergebnisse recht dürftig waren und das was ich gefunden 
(genau genommen war es nur eine Bibleothek und eine Ausarbeitung) habe 
nicht meinen Vorstellungen entsprochen hat, habe ich was eigenes 
aufgesetzt.

Wichtig war mir ein blockierendes Lesen und die Möglichkeit in einem 
Thread blockierend zu lesen und in einem anderen schreiben zu können.
Unter Windows wird dafür Overlapped IO benutzt. Unter Linux scheint es 
ohne weitere Maßnahmen zu funktionieren.


Die Linuximplementierung gefällt mir noch nicht so richtig.
Ich habe nicht so richtig rausbekommen, wie man beliebige baudraten 
einstellen kann. Zum anderen weiß ich nicht, wie ich das so 
konfigurieren kann, dass er unendlich lange blockiert, bis er alle 
Zeichen des read-requests bekommen hat.
VTIME geht nur maximal 25s. und wenn VMIN < bytesToRead-Param der Read 
Funktion ist, scheint auch undefiniert zu sein, was da passiert.
Deswegen wird jetzt VMIN auf 1 gestellt und im read Byteweise gelesen.

Dennoch ist das Ganze insgesamt auf einem Stand, in dem es mir momentan 
gut ausreicht, weswegen ich jetzt erstmal auf dem Stand lasse.

Wenn jemand Vorschläge/Verbesserungen hat, dann bin ich dafür offen und 
werde das sicherlich auch einpflegen.


Gruß,
Vlad

von Vlad T. (vlad_tepesch)


Angehängte Dateien:

Lesenswert?

hier der Source


an die mods:
sollte eigentlich an den ersten Beitrag.
das nachträgliche Anhängen per Editieren funktioniert nicht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Vlad Tepesch schrieb:
> das nachträgliche Anhängen per Editieren funktioniert nicht.

Für uns auch nicht. :-/

von linuxi (Gast)


Lesenswert?

vielen dank, genau so etwas habe ich gesucht!!!

von Vlad T. (vlad_tepesch)


Lesenswert?

Ach so,  was in der Linux Implementieurung auch noch fehlt, ist die 
Funktion zum auflisten der verfügbaren devices.

Die Möglichkeiten, die ich gefunden habe, basieren auf dem iterieren 
über alle /dev/ttySxx und /dev/ttyUSBxx Geräteknoten und dem Versuch 
diese zu öffnen. Das ist doch irgendwie Pfusch.

von Sven P. (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> Die Möglichkeiten, die ich gefunden habe, basieren auf dem iterieren
> über alle /dev/ttySxx und /dev/ttyUSBxx Geräteknoten und dem Versuch
> diese zu öffnen. Das ist doch irgendwie Pfusch.
Das ist harmlos.

Die Sache mit HKEY_LOCAL_MACHINE/HARDWARE/DEVICEMAP/SERIALCOMM ist ja 
auch  nur die halbe Wahrheit. Vor einer Weile stand ich vor demselben 
Problem (also Schnittstellen auflisten) und habe recherchiert.

Insgesamt musst du praktisch an neun verschiedenen Stellen suchen, um 
wirklich alle Ports zu finden:

[1] 
http://stackoverflow.com/questions/1388871/how-do-i-get-a-list-of-available-serial-ports-in-win32
[2] http://www.naughter.com/enumser.html

von Vlad T. (vlad_tepesch)


Lesenswert?

Sven P. schrieb:
> Die Sache mit HKEY_LOCAL_MACHINE/HARDWARE/DEVICEMAP/SERIALCOMM ist ja
> auch  nur die halbe Wahrheit.

> [2] http://www.naughter.com/enumser.html


die lib habe ich auch gefunden, fand es aber übertrieben.
Was soll ich mit einer Lib, die auf neun verschiedene Art und weisen die 
Comports sucht? ausßerdem ist mir an der Stelle egal, wie die Methode 
ist, was einen Benutzer interessiert, ist ja eine Liste.
Das ist der große Designfehler dieser Bibliothek.
Interessant wäre genau eine Funktion oder Methode,
die mir eine Liste zurückgibt.
Intern kann die Lib ja meinentwegen so viele Methoden benutzen, wie sie 
will - die gehören nur nicht ins Interface, dass sind Interna.


Sven P. schrieb:
> [1]
> http://stackoverflow.com/questions/1388871/how-do-...

Das hab ich auch gefunden. Genau deswegen habe ich auch die letzte 
Variante gewählt.

Für Windows gibts ja auch diese Pfuschvariante mit Namen aus "COM"+X 
bilden.
Nur dumm, dass die Ports beliebige Namen haben können. Die com0com haben 
defaultmäßig ja auch total schräge bezeichnungen, die dann von den 
ganzen Tools, die auf die Pfuschvariante setzen nicht gefunden werden.

Deswegen scheint mir das ganze auch unter Linux etwas fragwürdig. woher 
weiß ich denn, ob nicht nächtes Jahr eine serielle Schnittstelle auf 
Basis von Thunderbold erscheint, die dann /dev/ttyTB0 oder so heißt, 
oder irgendjemand die Geräteknoten einfach anders benennt.

Es muss doch auch irgendwie anders möglich sein.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Vlad Tepesch schrieb:
> die dann /dev/ttyTB0 oder so heißt,
> oder irgendjemand die Geräteknoten einfach anders benennt

Ich habe mich auch mal vor einiger zeit damit beschäftigt.
Über /proc/tty/drivers kann man sich eine solche Liste abrufen:
http://stackoverflow.com/questions/2530096/linux-how-to-find-all-serial-devices-ttys-ttyusb-without-opening-them
Es werden auch ein paar Alternative angerissen über dbus/hal

von Sven P. (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> Interessant wäre genau eine Funktion oder Methode,
> die mir eine Liste zurückgibt.
Naja, dann bau doch eine draus. Für was andres ist die Bibliothek da 
auch garnicht gedacht gewesen.


> Deswegen scheint mir das ganze auch unter Linux etwas fragwürdig. woher
> weiß ich denn, ob nicht nächtes Jahr eine serielle Schnittstelle auf
> Basis von Thunderbold erscheint, die dann /dev/ttyTB0 oder so heißt,
> oder irgendjemand die Geräteknoten einfach anders benennt.
>
> Es muss doch auch irgendwie anders möglich sein.
Mir käme da noch /proc/tty/drivers in den Sinn.
Vielleicht lässt sich über die Major/Minor auch noch was herausfiltern. 
Ginge jedenfalls schneller, als alle durchzuprobieren und jeweils 
irgendein ioctl() drauf zu machen, welches nur bei seriellen 
Schnittstellen funktioniert :-}

Läubi war schneller.

von Vlad T. (vlad_tepesch)


Lesenswert?

Läubi .. schrieb:
> Über /proc/tty/drivers kann man sich eine solche Liste abrufen:

Den Inhalt dieser Datei konnte ich nicht interpretieren
In der Doku steht nicht mal eine Spaltenbeschreibung.

Hab jetzt folgendes dazu gefunden:
http://lwn.net/images/pdf/LDD3/ch18.pdf

heißt das ich müsste in dieser Datei alle Einträge suchen, die in der 
letzten Spalte serial stehen haben? aus dem Produkt der Differenzen der 
beiden Paare aus den vorstehenden Spalten habe ich dann die maximale 
Anzahl an Geräten dieses Typs. Davor steht der Geräteknoten-Basisname

Was ich jetzt neu gelernt habe, ist das Verzeichnis
/sys/class/tty
zusammen mit dem obigen Wissen kann ich in dem Verzechnis nach 
Verzeichnissen suchen, in denen der Gerätebasisname vorkommt.

Läubi .. schrieb:
> Es werden auch ein paar Alternative angerissen über dbus/hal

das hal Zeugs scheint standardmäßig nicht installiert zu sein (und schon 
gar nicht auf einem kleinen embedded device

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Also "so einfach" ist das halt nicht machbar. Ich würde da pragmatisch 
vorgehen und das erst mal so implementieren das es auf deinen 
Zielgeräten zufriedenstellende Ergebnisse liefert.
Du kannst das ja hier auch noch ins SVN stellen, dann kann man das immer 
weiter verfeinern.

Vlad Tepesch schrieb:
> das hal Zeugs scheint standardmäßig nicht installiert zu sein
s.o. man kann versuchen das als zusätzliche Option einzubauen, 
letzendlich wird man aber auch wieder auf viele Optionen kommen welche 
man durchprobieren muss.
Ein paar passende Compileschalter für verschiedene Targets wirds 
vermutlich eh brauchen...

von Vlad T. (vlad_tepesch)


Angehängte Dateien:

Lesenswert?

hier eine Version 0.4

hab obigen Ansatz zum Finden von seriellen Geräten unter Linux mal 
implementiert.
wär toll, wenn ihr das mal bei euch auch mal testen könntet.

dann gabs noch eine kleine Interface-Änderung für die Funktion zum 
ermitteln der vorhandenen Seriellen Interfaces.

PortableSerialLib - Change Log
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  * fixed
  ~ changed
  + added
  - removed

v0.4
  ~ PSerLib_getAvailablePorts
    + added linux implementation for PSerLib_getAvailablePorts
    + added define for format of PSerLib_getAvailablePorts-Output
      (full path or just name)
    ~ changed interface of PSerLib_getAvailablePorts function to
      get additional pointer parameter to output number of found
      devices and return a error code.\n
      --> more consistency to all other functions.
    ~ more precise description of o_name parameter
      PSerLib_getAvailablePorts
  ~ set default baud rate of example/test program to a standard
    baud rate value

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Vlad Tepesch schrieb:
> Wichtig war mir ein blockierendes Lesen [...]

Du meinst wohl eher nicht-blockierendes Lesen, oder? Oder ein 
blockierendes Read mit Timeout?

> VTIME geht nur maximal 25s. und wenn VMIN < bytesToRead-Param der Read
> Funktion ist, scheint auch undefiniert zu sein, was da passiert.

Du willst einen Timeout implementieren? Nimm select().
Wenn Du weitere Fragen/Unklarheiten zur seriellen Schnittstelle unter 
Linux hast, frag mich einfach. Ich kenne die TTYs aus dem Effeff :-)

Gruß,

Frank

von Vlad T. (vlad_tepesch)


Lesenswert?

Frank M. schrieb:
> Du meinst wohl eher nicht-blockierendes Lesen, oder?

nö, ich mein es so, wie ich es geschrieben habe.
Ich will einfach einen Thread dafür abstellen, auf ewig auf Input von 
der uart zu warten.

von Karsten F. (Firma: von Dänemark) (bingo600)


Lesenswert?

Hi Vlad

Thanx for the nice library

However i have a small improvement suggestion

I have been using the library with an Arduino , and was always 
triggering an Arduino Reset when using your lib.

I have traced it to this function in PortableSerialLibLinux.c
1
  if(   (tcsetattr(io_port->port, TCSANOW, &newSettings)  < 0) 
2
     || (cfsetispeed(&newSettings, speed) < 0)
3
     || (cfsetospeed(&newSettings, speed) < 0))
4
  {
5
    return PSL_ERROR_configurePort;
6
  }

And changing it to
1
  if(   (cfsetispeed(&newSettings, speed) < 0)
2
     || (cfsetospeed(&newSettings, speed) < 0)
3
     || (tcsetattr(io_port->port, TCSANOW, &newSettings)  < 0))
4
  {
5
    return PSL_ERROR_configurePort;
6
  }

Solves the problem.

Before filling data in the struct , you zero'es the struct.
1
  memset(&newSettings, 0, sizeof(newSettings));  /* clear the new struct */

But according to this , setting a speed/baud to 0 (Seek B0), will clear 
DTR
http://www.easysw.com/~mike/serial/serial.html
http://homepages.cwi.nl/~aeb/linux/man2html/man3/termios.3.html

And in your code you call tcsetattr , before setting the speed , so the 
speed is zero , causing a DTR reset.


In my example i set the speed before calling tcsetattr , and now the 
Arduino isnt reset on opening the SerialPort.


Hope you will correct the nice library

Regards
Karsten Dänemark

von Vlad T. (vlad_tepesch)


Lesenswert?

Hi Karsten,
thank you for your feedback.

you are right, the linux part is not very well testet.
I only used it on my fritzbox (dsl-router) to communicate over an usb 
uart adapter with some homemade device.

please could you post the complete changed file?

best regards
vlad

von Karsten F. (Firma: von Dänemark) (bingo600)


Angehängte Dateien:

Lesenswert?

Hi Vlad

Here is the new file & a diff file

Regards
Karsten

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.