Pyserial Tester

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
Benutzeravatar
wuf
User
Beiträge: 1420
Registriert: Sonntag 8. Juni 2003, 09:50

Samstag 5. Juli 2008, 10:09

Hallo Forumfreunde

Ich musste mich in das pyserial 2.2 Modul einarbeiten. Bei dieser Gelegenheit integrierte ich noch trainingshalber Komponenten aus dem Tkinter-GUI-Toolkit für den Aufbau der Benutzeroberfläche und entstand dieses kleine Testprogramm. Ich möchte es hier frei zur Verfügung stellen evt. kann es noch jemand interessierter gebrauchen.

(Be aware i am working with an outcasted GUI-Tool-Kit !) :lol:

Ich möchte das pyserial Modul benutzen um digitale Daten für Visualisierungs- und Steuerungszwecke auf ein Mikrokontroller-System zu senden und von dort auch wieder Daten zu empfangen.

Mein Testprogramm sendet ein Telegramm zyklisch aus und empfängt es wieder als Loopback-Signal über die gleiche Schnittstelle. (Pin TX mit RX verbunden) Das Telegramm setzt sich wie folgt zusammen:

a) Präamble-Byte
b) Databyte-1 (Mit Schalterdaten 0...7)
c) Databyte-2 (Mit Schalterdaten 8...15)
d) CRC-16 (Highbyte)
e) CRC-16 (Lowbyte)

Habe das Programm getestet mit:
SuSE 10.0 und 10.3
Windows XP
(Unter Windows kann die Benutzeroberfläche grafisch von der unter Linux abweichen, speziell Objekteigenschaften von Ziehleisten werden vom Windows-Grafik-Manager vorgegeben)
Python 2.4

Meine Entwicklungs-Plattform hier ist:
SuSE 10.0, KWrite, Terminal-Konsole und Python 2.4

Hier der Code:
[Code ausgelagert]

Gruss wuf :wink:
Take it easy Mates!
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Samstag 5. Juli 2008, 10:25

Code: Alles auswählen

class ComGui(object):
    """GUI für die Visualisierung der Seriellen Kommunikation"""

    def __init__(self,
        com_config = [],
        ports      = [],
        callback   = None
        ):
Das funktioniert nicht.

Beispiel:

Code: Alles auswählen

#!/usr/bin/env python

def foo(bar=[]):
    bar.append('foo')
    print bar
    
for dummy in xrange(5):
    foo()
Ausgabe:

Code: Alles auswählen

['foo']
['foo', 'foo']
['foo', 'foo', 'foo']
['foo', 'foo', 'foo', 'foo']
['foo', 'foo', 'foo', 'foo', 'foo']
Default-Argumente müssen Immutables sein, da sie zur Compiletime erstellt werden. Man verändert also immer das selbe Objekt, was bei Immutables aber nicht weiter schlimm ist.

Code: Alles auswählen

def foo(bar=None):
    """ @param bar: defaults to []
    """
    if not bar:
        bar = []
    bar.append('foo')
    print bar
    
for dummy in xrange(5):
    foo()
Außerdem kannst du Konstanten auch auf Modul-Ebene ablegen. Sind ja vom semantischen her keine Instanz-Attribute. Evtl. passen sie auch gut auf Klassenebene als statische Variablen, aber dafür ken ich das Program zu wenig :]

Außerdem sieht das hier z.B. unschön aus:

Code: Alles auswählen

        self.tx_data_list    = [
            {
            'name'           : self.TEXT_PREAMBLE,
            'name_label_obj' : None,
            'data_label_obj' : None,
            'hex_label_obj'  : None,
            },
            {
            'name'           : self.TEXT_DATA_BYTE1,
            'name_label_obj' : None,
            'data_label_obj' : None,
            'hex_label_obj'  : None,
            },
            {
            'name'           : self.TEXT_DATA_BYTE2,
            'name_label_obj' : None,
            'data_label_obj' : None,
            'hex_label_obj'  : None,
            },
            {
            'name'           : self.TEXT_CRC_HIGH,
            'name_label_obj' : None,
            'data_label_obj' : None,
            'hex_label_obj'  : None,
            },
            {
            'name'           : self.TEXT_CRC_LOW,
            'name_label_obj' : None,
            'data_label_obj' : None,
            'hex_label_obj'  : None,
            },
            ]
Und Icons, etc lieber auf Modulebene, sodass sie nicht stören. Im Konstruktor haben die jedenfalls nichts verloren.
Auch ist ein knap 900-Zeilen Konstruktur etwas...arg :D
lunar

Samstag 5. Juli 2008, 10:57

audax hat geschrieben:Default-Argumente müssen Immutables sein, da sie zur Compiletime erstellt werden.
Müssen nicht, man kann ja auch eine Absicht dahinter unterstellen. Man könnte argumentieren, dass veränderbare Default-Argument als funktionsglobale Closures wirken ;)
Man verändert also immer das selbe Objekt, was bei Immutables aber nicht weiter schlimm ist.
Das klingt etwas abenteuerlich ;) Immutables kann man ja gar nicht verändern, wie kann Veränderung da schlimm sein ;)

Bei unveränderbaren Default-Argumenten kann man das ursprüngliche Objekt ja eben _nicht_ verändern, sondern nur den Namen neu binden.
Außerdem kannst du Konstanten auch auf Modul-Ebene ablegen. Sind ja vom semantischen her keine Instanz-Attribute. Evtl. passen sie auch gut auf Klassenebene als statische Variablen, aber dafür ken ich das Program zu wenig :]
Naja, eine Konstante, die nur in einer Klasse eine Bedeutung hat, ist imho als Klassenattribut besser platziert.
Auch ist ein knap 900-Zeilen Konstruktur etwas...arg :D
Full ack ;) 900 Zeilen sind einfach nur krass, um so mehr, da er das ganze Ding offenbar mit _KWrite_ geschrieben hat :shock: Ich bin verdammt beeindruckt, dass er da noch den Durchblick behalten hat ;)

Ich würde sogar sagen, dass die Icons und eventuell sogar der ganze GUI Code in einem eigenen Modul wesentlich besser aufgehoben sind. So wie 900 Zeilen für einen Konstruktor krass sind, sind auch 2100 Zeilen etwas krass für ein Modul.

Mit einem vernünftigen setuptools-Skript kann man die Icons eigentlich auch sehr komfortabel als "package data" installieren und über pkg_resources laden. Ich persönlich finde es jedenfalls weder übersichtlich noch elegant, Icons in den Code einzubetten. Imho sollte das Programm schon im Sinne der Les- und Wartbarkeit in mehrere Teilmodule aufgesplittet werden. 2100 Zeilen lese ich nicht "mal eben so" ;)
Benutzeravatar
wuf
User
Beiträge: 1420
Registriert: Sonntag 8. Juni 2003, 09:50

Samstag 5. Juli 2008, 11:51

Hallo audax und lunar.

Danke für eure interressanten Tipps und Anregungen. Die Icons lagere ich normalerweise in ein separates Image-Library-Modul aus. Die einzelnen Klassen können natürlich auch in einzenen Module untergebracht werden. Da hier die Tkinter-Widget mit direkt lesbaren Code Pur im Modul integriert sind braucht es natürlich ein bisschen Platz. Man könnte natürlich für die Widget-Code-Fragmente den ganzen Zeilen-Hub von 80 Zeichen nutzen, dann gebe es im ganzen auch weniger Anzahl Zeilen. Die Lesbarkeit würde aber so negativ beeinträchtigt, dass der Autor nach ein paar Wochen sich selber wundern würde was er da einmal geschrieben hat. Ich möchte den Code auch noch im Altersheim lesen können um Codefragmente davon abstrahieren zu können um zum Beispiel ein Programm für die Pilleneinnahme zu schreiben. :lol:

Hier fürs Forum wollte ich das Programm in einem Stück zusammen-schmieden ohne einer Unmenge von Dateien. So, dass ich das Programm nicht in 50 KWrite-Fenstern zusammenlesen muss, was die Übersicht auch nicht gerade steigert.

Bei Tkinter wird halt nicht wie bei einen IDE-Unterstützen Plattform der ganze GUI-Lastige Codemüll in diversen dll's oder Dateien mit verschleiertem Inhalt versteckt.

Noch eine peinliche Frage. Habt ihr das Skript ausprobieren können? Funktioniert es bei euch? Würde mich auch sehr interessieren.

Auf jeden Fall vielen Danke für eure Antworten. Kritik, Verbesserungsvorschläge, Anregungen, Tipps usw. sind jederzeit herzlich willkommen.

Beste Grüsse wuf :wink:
Take it easy Mates!
lunar

Samstag 5. Juli 2008, 13:22

wuf hat geschrieben:Bei Tkinter wird halt nicht wie bei einen IDE-Unterstützen Plattform der ganze GUI-Lastige Codemüll in diversen dll's oder Dateien mit verschleiertem Inhalt versteckt.
Im Interesse der Trennung von GUI und Logik sollte man auch bei Tkinter-Programmen GUI und Logik in separate Module packen. Btw, man kann in jedem Toolkit GUI-Code manuell schreiben. Ob das sinnvoll ist, sei mal dahingestellt, ich persönlich nutze lieber WYSIWYG-Designer. GUI-Code zu schreiben ist einfach furchtbar langweilig ...

2000 Zeilen sind für ein Modul einfach zu lang. Es hätte dem Posting keinen Abbruch getan, dass Ganze auf drei Pastes zu verteilen ;)

Ausprobieren kann ich das nicht ... mein Python hat kein Tk und außerdem wüsste ich nicht, was ich an die serielle Schnittstelle stöpseln sollte ;)
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Samstag 5. Juli 2008, 13:48

lunar hat geschrieben:
audax hat geschrieben:Default-Argumente müssen Immutables sein, da sie zur Compiletime erstellt werden.
Müssen nicht, man kann ja auch eine Absicht dahinter unterstellen. Man könnte argumentieren, dass veränderbare Default-Argument als funktionsglobale Closures wirken ;)
Wäre es Absicht, müsste da wirklich ein ordentlicher Kommentar zu stehen ;)
Man verändert also immer das selbe Objekt, was bei Immutables aber nicht weiter schlimm ist.
Das klingt etwas abenteuerlich ;) Immutables kann man ja gar nicht verändern, wie kann Veränderung da schlimm sein ;)

Bei unveränderbaren Default-Argumenten kann man das ursprüngliche Objekt ja eben _nicht_ verändern, sondern nur den Namen neu binden.
Tut mir ehrlich leid, dass ich mich dermaßen ungenau ausgedrückt habe...
Ich halte mich zukünftig zurück, wenn ich gerade keine Zeit für Romane hab.
Außerdem kannst du Konstanten auch auf Modul-Ebene ablegen. Sind ja vom semantischen her keine Instanz-Attribute. Evtl. passen sie auch gut auf Klassenebene als statische Variablen, aber dafür ken ich das Program zu wenig :]
Naja, eine Konstante, die nur in einer Klasse eine Bedeutung hat, ist imho als Klassenattribut besser platziert.
Was hab ich denn anderes gesagt? Ich meinte doch, er sollte die als statische Klassenattribute ablegen...
lunar

Samstag 5. Juli 2008, 14:04

audax hat geschrieben:
lunar hat geschrieben:
audax hat geschrieben:Default-Argumente müssen Immutables sein, da sie zur Compiletime erstellt werden.
Müssen nicht, man kann ja auch eine Absicht dahinter unterstellen. Man könnte argumentieren, dass veränderbare Default-Argument als funktionsglobale Closures wirken ;)
Wäre es Absicht, müsste da wirklich ein ordentlicher Kommentar zu stehen ;)
:D Mein Kommentar war nicht ganz ernst gemeint, wer Default-Argument als Funktions-globale Closures missbraucht, hat imho ein ernsthaftes Problem bei der Strukturierung seines Codes ;) Selbst wenn da ein Kommentar steht ...
Außerdem kannst du Konstanten auch auf Modul-Ebene ablegen. Sind ja vom semantischen her keine Instanz-Attribute. Evtl. passen sie auch gut auf Klassenebene als statische Variablen, aber dafür ken ich das Program zu wenig :]
Naja, eine Konstante, die nur in einer Klasse eine Bedeutung hat, ist imho als Klassenattribut besser platziert.
Was hab ich denn anderes gesagt? Ich meinte doch, er sollte die als statische Klassenattribute ablegen...
Stimmt, hab dein Posting nicht so genau gelesen... my bad.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Samstag 5. Juli 2008, 14:09

wuf hat geschrieben:Noch eine peinliche Frage. Habt ihr das Skript ausprobieren können? Funktioniert es bei euch? Würde mich auch sehr interessieren.
Bei mir läuft es, wobei "läuft" heißt, dass man eine aufgeräumte Oberfläche sieht und beim Versuch des Verbindens mit der seriellen Schnittstelle eine ordentliche Fehlermeldung erhält mit nettem Symbol daneben, das das jetzt nicht geklappt hat.

Optisch finde ich es sehr ansprechend gemacht. Ob es dann auch technisch funktioniert kann ich nicht sagen. Ich wüsste leider auch gar nicht, was ich tun sollte, um das zu testen ... :oops:
Benutzeravatar
wuf
User
Beiträge: 1420
Registriert: Sonntag 8. Juni 2003, 09:50

Samstag 5. Juli 2008, 14:20

Hallo lunar

Ich finde es merkwürdig, dass bei deiner Python Installation das Tkinter-Package nicht mitinstalliert wurde, da muss sicher etwas schiefgelaufen sein. :lol:

Wegen GUI und Logik-Trennung. Könntest du mir bitte einige kurze Tipps bezogen auf mein Skript geben. Natürlich nur wenn du ein paar Minuten freie Zeit verfügbar hast. Ich bin gierig um etwas lernen. Ich möchte meine Programmkünste auf eine höher Ebene bringen ohne mich von Tkinter trennen zu müssen.

OK. Es wird immer jene geben die mit einem schönen Ferrari mit allem drum und dran ohne viel Platz für einen Koffer zu haben herumzufahren und es gibt aber auch immer solche die das lieber in einem Oldtimer (Göppel) mit der Werkzeugkiste und Taschenlampe im Kofferraum tun. Und ein wenig Oel und Fett an den Händen macht doch Spass. Oder? :lol:

OK. Vielen Dank für deine Bemühung. Gruss :wink:
Take it easy Mates!
lunar

Samstag 5. Juli 2008, 14:33

wuf hat geschrieben:Ich finde es merkwürdig, dass bei deiner Python Installation das Tkinter-Package nicht mitinstalliert wurde, da muss sicher etwas schiefgelaufen sein. :lol:
Nein, dass ist in voller Absicht so geschehen. Gentoo hat einen "tk"-Useflag, den man deaktivieren kann, wenn man – so wie ich – tk nicht braucht.
Wegen GUI und Logik-Trennung. Könntest du mir bitte einige kurze Tipps bezogen auf mein Skript geben. Natürlich nur wenn du ein paar Minuten freie Zeit verfügbar hast.
Die Icons gehören in ein eigenes Modul, das ist noch nicht mal Code, genau genommen sind das Daten. Un generell alles, was zur GUI gehört. Für eine detaillierte "Analyse" ist mir dein Skript ehrlich gesagt zu lang.

Btw, ob du Tkinter nutzt oder nicht, ist mir egal, ich versuche nicht, dir das auszureden ;) Du kannst die Seitenhiebe also lassen ;)
Benutzeravatar
wuf
User
Beiträge: 1420
Registriert: Sonntag 8. Juni 2003, 09:50

Samstag 5. Juli 2008, 14:59

Hallo numerix

First of all. Ich habe das mit dem Menu-Item undShortcut noch nicht abgeschrieben. Wie du siehst wollte ich noch ein anderes Projekt durchziehen.

Wenn du eine Fehlermeldungsanzeige hast funktioniert doch immerhin etwas.

Frageb:

a) Hast du noch eine serielle Schnittstelle auf deinem PC-System? Ich weiss diese Frage ist in der heutigen Zeit ein wenig verrufen. Ich weiss auch nicht ob du mit Mikrokontrollern zu tun hast. Bei den Lowend Kontrollern steht meistens nur eine RS232 als Verbindungsmöglichkeit zu einem PC zur Verfügung.

b) Hast du einen USB-RS232 (seriell) - Konverter? Vermutlich nicht. Braucht es natürlich nur, wenn du entsprechende externe Hardware mit deinem PC, welcher heute nur noch USB-Schnittstellen besitzt, verbinden musst.

c) Hast du einen Notebook der noch ein internes MODEM besitzt? Unter Windows ist diesem MODEM ein internes COM-Port zugeteilt. Bei mir ist das COM-3. Wenn du mein Programm unter Windows startest und als Schnittstelle dieses COM-Port verwendest sollte es die gesendeten Daten über den Loopback automatisch zu meinem Programm zurücksenden. Das heisst die Fehlermeldung auf der GUI sollte
auf 'Die Verbindung ist OK' wechseln.

Wenn eine Verbindung besteht muss eine aktivierte Checkbox auf der TX-Eingabe auf der RX-Ausgabe angezeigt werden. Die Kommunikation wird über die Schaltfläche 'COM-Ein' gestartet. Ist die Verbindung OK, muss das Steckersymbol zusammen gesteckt sein.

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
wuf
User
Beiträge: 1420
Registriert: Sonntag 8. Juni 2003, 09:50

Samstag 5. Juli 2008, 15:13

Hallo lunar

Ich wollte dich nicht verletzen und entschuldige mich dafür, wenn du mein Post als Seitenhieb aufgefasst hast.

Es ist mir auch klar das base64-codierte Icons kein Code ist sondern Daten. Wenn man es so akribisch genau nimmte ist ein Python-Skript auch kein Code sondern sondern nur simple Daten.

Danke für deine Antwort Gruss wuf :wink:
Take it easy Mates!
lunar

Samstag 5. Juli 2008, 16:19

wuf hat geschrieben:Ich wollte dich nicht verletzen und entschuldige mich dafür, wenn du mein Post als Seitenhieb aufgefasst hast.
So war das nicht gemeint, ich fühle mich nicht "verletzt" ;) Ich hatte nur das Gefühl, dass du seit unserem Disput über Tk immer glaubst, ich wolle dir Tk ausreden ;) Ich wollte klarstellen, dass dem nicht so ist, weil ich das Gefühl hatte, dass _du_ dich verletzt fühlst ;)

Ich würde mal sagen, wir haben uns kolossal missverstanden ;)
Benutzeravatar
wuf
User
Beiträge: 1420
Registriert: Sonntag 8. Juni 2003, 09:50

Montag 7. Juli 2008, 15:06

Hallo Forumfreunde

Habe den Pyserial-Tester noch unter SuSE 10.0 mit Python 2.5 ausgetestet und stellte fest, dass Tkinter betreffs grafischem Verhalten näher an Windows gebracht wurde, dies betrifft hauptsächlich das CheckBox-Widget. Ich passte den Pyserial-Tester hierfür an. Gleichzeitig stellte ich fest, dass nach dem aktivieren der Schaltfäche 'TX-Löschen' ein Problem besteht. Habe auch noch diesen Fehler behoben.

Hier die neue Version pyserial_tester_01_02_02.py:

[Code ausgelagert]

Gruss wuf :wink:
Take it easy Mates!
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Sonntag 13. Juli 2008, 18:49

lunar hat geschrieben:
wuf hat geschrieben:Ich finde es merkwürdig, dass bei deiner Python Installation das Tkinter-Package nicht mitinstalliert wurde, da muss sicher etwas schiefgelaufen sein. :lol:
Nein, dass ist in voller Absicht so geschehen. Gentoo hat einen "tk"-Useflag, den man deaktivieren kann, wenn man – so wie ich – tk nicht braucht.
Ich habe ebenso das Paket python-tk nicht installiert, da ich es nicht brauche und es auch keine Programme gibt die ich nutzte, die das nutzen würden - daher ist es auch nicht vorhanden. Das ist auch sehr nützlich auf Serversystemen, da python-tk im Endeffekt die ganzen Xlibs mitzieht, die man auf solchen Systemen nicht braucht und die Unnötig Kapazität verschwenden.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Antworten