easy-forum

Deutsch - Software => Kommunikation => Programmierung mit EASY_COM.dll => Thema gestartet von: Spellbreaker am April 19, 2012, 09:26:15 Vormittag

Titel: Raspberry Pi + Easy
Beitrag von: Spellbreaker am April 19, 2012, 09:26:15 Vormittag
Moin moin!

Da ja nun das Release des Raspberry Pi (http://de.rs-online.com/web/generalDisplay.html?id=raspberrypi) kurz bevor steht, und ja mit rund 30 Euro extrem günstig ist, frage ich mich natürlich ob es eine Möglichkeit gibt zusammen mit ner EASY-209-SE das Teil als eine Art Datenlogger zu nutzen.

Gibt es auch eine Andere Möglichkeit als über die DLL mit der Easy zu kommunizieren? Auf dem Raspberry läuft ein Linux System (ARM Prozessor).

Hat sich da mal jemand Gedanken drüber gemacht? Ist nur so ein Gedankenspiel....

Gruß,

Nico Blanke
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am April 18, 2013, 18:30:30 Nachmittag
Hi Nico!

deine Nachricht ist schon ein Jahr alt... Mann, wie die Zeit vergeht :-\

Ich finde auch, dass sich das Raspi geradezu anbieten würde, um neben einer Easy auf der Schiene zu hängen, und einen wunderbaren Web-Bedienoberflächen-Server hergeben täte.

Leider wird uns kein Linux-Treiber gegönnt.

Ich bin dennoch so begeistert von der Idee, dass Ich mir ein Haufen dicker Bücher und einen Raspi gegönnt habe. Einen USB sniffler habe ich auch bereits. Aber voraussichtlich nicht genügend Grips, und das kann man nirgends kaufen  :(

Eine extrem dilettantische, aber sehr spaßige Lösung hätte ich noch als Alternative für die ( wenn auch langsame und unwirtschaftliche) Kommunikation Raspi - Easy:

Mit zwei Easy Ausgängen und zwei Easy Eingängen eine Art serielle Kommunikation an GPIO basteln.  :o

Lächerlich? ;D

Ich werde berichten.

Gr5uss,

Peter  

P.S.: ich entdeckte gerade den SP Baustein (Serielles Protokoll). Leider funktioniert es nur in einer Richtung (raus) ... und ist sehr Speicherplatz-intensiv: man benötigt pro "Datensatz" einen SP- und einen D- (Text) Baustein.

Ein USB Datenlogger müsste sich damit aber realisieren lassen: Wenn ich es richtig verstanden habe, kann man, pro SP&D Paar, 4 werte übertragen (falls gewünscht mit Zeitstempel!)

Titel: Re:Raspberry Pi + Easy
Beitrag von: Spellbreaker am April 19, 2013, 08:45:37 Vormittag
Wie schon in deinem anderen Posting geschrieben ist die Kommunikation mit der von Eaton zur Verfügung gestellten Spezifikation über USB völlig unproblematisch
Titel: Re:Raspberry Pi + Easy
Beitrag von: arnenrw am Mai 02, 2013, 14:48:28 Nachmittag
Netterweise gibts eine Protokollbeschreibung für die Serielle Kommunikation.
USB ist auch nichts anderes.

ftp://ftp.moeller.net/EASY/TOOLS/Index.html

Im Besonderen die CPP Anwendung sollte da weiterhelfen
EASY_COM_V250\Demo.cpp

SORRY ist anscheinend nur für Windofs mit DLL

Viel Glück

Arne
Titel: Re:Raspberry Pi + Easy
Beitrag von: arnenrw am Mai 02, 2013, 17:07:38 Nachmittag
Hab mich mal näher mit befasst und die serielle Schnittstelle mit einem Monitor (Free Serial Port Monitor serial-port-monitor[punkt]com) überwacht.

Folgender Datenmüll ist bei 4800 Baud entstanden (Hexadezimal):
Art   ;   Bitmuster Bit 16……1   ;   PC -> SPS   ;   SPS -> PC
Eingänge   ;   oooooooo;   C1 81 08 0C 00 95   ;   C0 14 08 00 00 00 00 00 00 00 00 1C
Eingänge   ;   ooooooox   ;   C1 81 08 0C 00 95    ;   C0 14 08 01 00 00 00 00 00 00 00 1D
Eingänge   ;   xooooooo   ;   C1 81 08 0C 00 95    ;   C0 14 08 80 00 00 00 00 00 00 00 9C
Eingänge   ;   xxxxxxxx   ;   C1 81 08 0C 00 95   ;   C0 14 08 FF 00 00 00 00 00 00 00 1C
P-Taste   ;   ooox           ;   C1 81 08 0C 00 95    ;   C0 14 08 80 00 00 01 00 00 00 00 9D
P-Taste   ;   ooxo           ;   C1 81 08 0C 00 95    ;   C0 14 08 80 00 00 02 00 00 00 00 9E
Merker   ;   oooooooo xxxxxxxx    ;   C1 81 07 14 00 9C    ;   C0 14 07 FF 00 00 00 00 00 00 1B
Merker   ;   oooooooo oooooooo;   C1 81 07 14 00 9C   ;   C0 14 07 00 00 00 00 00 00 00 1B
Merker   ;   oooooooo ooooxxxx;   C1 81 07 14 00 9C   ;   C0 14 07 0F 00 00 00 00 00 00 2A
Merker   ;   ooooxxxx oooooooo;   C1 81 07 14 00 9C   ;   C0 14 07 00 0F 00 00 00 00 00 2A 
Merker   ;   xxxxoooo oooooooo;   C1 81 07 14 00 9C   ;   C0 14 07 00 F0 00 00 00 00 00 0C
Ausgang   ;   ooooxxxx   ;   C1 81 07 14 00 9C   ;   C0 14 07 00 00 0F 00 00 00 00 2A
Ausgang   ;   oooooooo;   C1 81 07 14 00 9C   ;   C0 14 07 00 00 00 00 00 00 00 1B
Ausgang   ;   ooooooox   ;   C1 81 07 14 00 9C   ;   C0 14 07 00 00 01 00 00 00 00 1C
Ausgang   ;   ooooxooo   ;   C1 81 07 14 00 9C   ;   C0 14 07 00 00 08 00 00 00 00 23
   ;      ;      ;   
Analog   ;   I7=10V   ;   C1 81 02 09 00 8C    ;   C0 14 02 64 03 7D
Analog   ;   I7=5V   ;   C1 81 02 09 00 8C    ;   C0 14 02 32 03 4B
Analog   ;   I7=0,4V   ;   C1 81 02 09 00 8C    ;   C0 14 02 04 03 1D
Analog   ;   I8=0,3V   ;   C1 81 02 09 00 8C    ;   C0 14 02 03 03 1C
Analog   ;   I8=5V   ;   C1 81 02 09 00 8C    ;   C0 14 02 04 31 4B
Analog   ;   I8=10V   ;   C1 81 02 09 00 8C    ;   C0 14 02 04 64 7E

Wenn ich weiter forsche kann ich auch die restlichen Gerätedaten auslesen. Ist halt aufwändig. Wenn jmd eine Klasse in C oder VB schreiben will, kann ich gerne den Rest rausfinden.

Gruß Arne
Titel: Re:Raspberry Pi + Easy
Beitrag von: Spellbreaker am Mai 03, 2013, 08:35:10 Vormittag
Wozu der Aufwand?

Nochmal: Einfach bei Eaton anrufen bzw. hinschreiben, und man erhält eine NDA, und wenn man diese unterschreibt, erhält man eine komplette und vollständige Protokollspezifikation.

Ausserdem glaube ich nicht das so ein öffentliches reverse-engineering gerne gesehen ist. Zumal es völlig unnötig ist.

lg,

Spellbreaker
Titel: Re:Raspberry Pi + Easy
Beitrag von: arnenrw am Mai 03, 2013, 08:36:43 Vormittag
letzte Aussage von Eaton war leider eindeutig NEIN zu der Herausgabe des Protokolls. Wenns jmd geschafft hat kann er es gerne mitteilen.
Titel: Re:Raspberry Pi + Easy
Beitrag von: Spellbreaker am Mai 03, 2013, 08:39:07 Vormittag
Ich habs hier doch liegen.
"easyCom Kommunikationsprotokoll easy800/MFD, easy500/700 und easySafety". Abteilung IAB-PDSE erstellt am 08.11.2011 .

War kein Problem das zu bekommen, wie gesagt NDA musste unterschrieben werden.
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am Mai 22, 2013, 23:18:06 Nachmittag
Hallo Spellbreaker und Arne!

ich habe gar nicht gemerkt, dass hier was los war ...

Bis jetzt war mein Problem viel weniger das Protokoll, als überhaupt eine Verbindung zwischen Raspi (unter Wheezy Raspbian) und Easy800, mittels USB-CAB zu erreichen.

Gleichzeitig habe ich versucht zu lernen, mit einer Linux Maschine klar zu kommen (nicht leicht für einen unterdurchschnittlich begabten MS-Office-User).

Aber es macht einfach Spaß mit Linux  :D

Einen Einblick in irgendwelche Moeller Protokollbeschreibung oder Quellcode finde ich zur Zeit für mich nicht wünschenswert, da jede Zeile die ich in diesem Sinne schreiben würde, unter Verdacht stehen könnte, dass ich mich nicht an das "Non Disclosure Agreement" gehalten habe.

Ich finde: lieber "Grauzone" fahren als "Dunkelgrauzone" fahren.

Wie Spellbreaker angedeutet hat, ist alles - bis jetzt - ziemlich einfach.

Bis jetzt habe ich folgendes rausgefunden:

In meinem Fall (Easy800 + USB-CAB) habe ich, auf dem Raspberry Pi, pySerial installieren müssen, da ddas USB-CAB auf einem Silicon-Labs CP2102 chip basiert, also eigentlich kein schlichtes USB Kabel ist, sondern ein USB-Serial Umwandler... das ist auch besser, weil Serielle Kommunikation einfacher ist als USB. (ausserdem ist Python für mich erträglicher als C)

Jedenfalls, ich muss nicht die Easy ansprechen, sondern einen Silabs Chip am anderen Ende des Kabels...

Der CP210x Treiber ist auch seit langem auf Debian standardmäßig vorhanden (Bingo!).

Der Treiber hört leider nicht auf die IDs vom EASY USB-CAB (188A:3001) und lässt sich auch nicht durch die Parameter, die an "modprobe" übergeben werden (vendor=xxxx product=xxxx), beeinflussen.

Aus Norwegen bekam ich einen entscheidenden Tipp ( http://www.ha19.no/usb/  danke Jon!):

Easy einstöpseln und als „root“ eingeben:

echo 188A 3001 > /sys/bus/usb-serial/drivers/cp210x/new_id

Voilá! Schon wird der Treiber meinem Kabel zugewiesen! (oder umgekehrt?) und ich habe ein neues Port "/dev/ttyUSB0" (Windoze würde es "COMsonstwas" nennen)

 ;)

Um ehrlich zu sein : weit habe ich es seitdem noch nicht bekommen...

Bisher (vor einigen Stunden) habe ich nur einen Merker (und zwar nur M09) schreiben können, dank dieses Mittschnitts aus der Windoze USB Kommunikation (merke: USB ... nicht Seriell)

Wann immer die Easy-Com.dll den M09 mit "1" beschrieb, hatte ich einen Bulk-Transfer mit folgender Payload :

0x45 0x08 0x20 0x00 0x04 0x08 0x00 0x01 0xCF 0x92

Das habe ich dann einfach auf mein neues "/dev/ttyUSB0" Port geschrieben

Dafür war mein Python "test_1.py":

import serial

s =serial.Serial('/dev/ttyUSB0', baudrate = 9600, timeout = 0)

d = '\x45\x08\x20\x00\x04\x08\x00\x01\xCF\x92'

Nicht die Welt: Ganz schlichte pySerial default-Verbindung

Dann habe ich in die  Python Shell eingegeben :

>>> s.write(d)

Antwort >>> 10

... d.h.: 10 byte geschrieben, nicht zu verwechseln mit : "Easy hat 10 byte gelesen und verstanden"

aber

>>> s.read(10)

gab exakt dieselbe Antwort wie das Windoze Vorbild... und tatsächlich! M09 war auf "1" gesetzt  ;D

Übrigens, das erste Byte in der Folge beim Schreiben ist 0x45 .... also "E"
das erste Byte beim Lesen ist 0x65 ... also "e"

 8) ... na, wenn das nicht bedeuten will, dass ich auf dem richtigen weg bin ...

Ich hoffe, das hilft beim Basteln!

Gruß

Peter


P.S.:

Nicht dass jemand denkt, ich hätte die Welt erfunden oder irgendwelche Schutzmaßnahmen umgangen. Für dieses Bastel-Projekt habe ich mir einen Extra-Reiter in der M$IE Favoritenliste angelegt, und der ist nach einigen Wochen hiermit populiert (vielen Dank an diese Leute!):

http://easycalculation.com/hex-converter.php
http://pyusb.sourceforge.net/docs/1.0/tutorial.html
http://wiki.ubuntuusers.de/Kernelmodule
http://www.raspberrypi.org/phpBB3//viewtopic.php?f=31&t=25356
http://pyserial.sourceforge.net/
http://www.usbmadesimple.co.uk/ums_4.htm
http://www.ha19.no/usb/
http://learn.adafruit.com/hacking-the-kinect/command-number-1-and-2-led-blinky
http://www.etheus.net/CP210x_Linux_Driver
https://sppyqt.googlecode.com/files/Python%20for%20Serial%20Communication.pdf
http://stackoverflow.com/questions/16633868/sending-binary-data-over-a-serial-connection-with-pyserial/16635275#16635275
http://elinux.org/Serial_port_programming
http://stackoverflow.com/questions/11763295/sending-command-parameters-to-serial-port-using-python?rq=1

 ::) Manches davon ist ein Überbleibsel von der Zeit, als ich dachte, dass ich über USB an "das Ding" kommen könnte. Gelöscht habe ich auf jeden fall Links zu Forum einträgen wie folgendes:

<Frage> (...) weiss jemand wie man Binäre Daten über pySerial überträgt?
<Antwort> Ja

 ??? Na, klasse!!!
Titel: Re:Raspberry Pi + Easy
Beitrag von: arnenrw am Mai 23, 2013, 09:06:14 Vormittag
Ich hab immer noch keine Antwort von Moeller und das schon seit 2 Wochen. Naja vlt schlafen die zur Zeit oder sind im Urlaub ;-)

Da ich das Protokoll auseinandergeflückt habe und jetzt eine Visualisierungsumgebung suche, bin ich auf pvbrowser (punkt) de gestossen.
Hier müsste man nur noch den seriellen Teil des Modbus Dienst umstricken (läuft Seriell oder über TCP) und schon könnte es losgehen.
Wenn jetzt noch genügend Zeit übrig wäre ;-)

Achja ich nutze die VM Emulation des Raspy, so geht die Entwicklung wesendlich schneller
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am Mai 26, 2013, 02:25:02 Vormittag
Arne,

also, wenn Du das Easy Protokoll wirklich "auseinandergepflückt" hast, dann gratuliere ich, und hoffe, dass dich kein NDA daran hindert, deine Erkentnisse mit uns zu teilen.
 
Ich bin in den letzten Tagen nicht besoders weit gekommen...  ::)

Ich kann zwar unter Windoze "geschnüffeltes" mit Erfolg wiederholen, komme aber nicht dahinter, wie ich beliebige Anweisungen selbst zusammensetzen kann.

Mein Aufbau besteht aus Easy800 + Easy USB-CAB. Das ist vielleicht anders als Deiner...

Um einen bestimmten Merker zu setzen, weiss ich, dass ich folgende Sequenz schreiben müsste

0x45 (oder "E") ..... möglicherweise als Ankündigung einer Übertragung an Easy (?)
0x08 ... Länge der darauf folgenden Bytes
0x20 ... bedeutet wohl, dass ich auf das Prozzessabbild der Easy schreiben will (0x00 dass ich lesen will)
0x00 ... ist vielleicht der Teilnehmer (kann ich nicht überprüfen)
0x04 ... bedeutet, ich will einen einzelnen Bit schreiben (.object)
0x00 ... ist der Index des Merkers (Basis 0, also hier M1)
0x00 ... hat bei .object 0x04 keine bedeutung <--- Falsch (ist der zweite Byte des Index)
0x01 ... bool 1 (0x00 dann bool 0)

 >:( dann sind aber noch zwei bytes nötig (in diesem Fall 0xCF und 0x92) die meiner Meinung nach rechnerisch ermittelt werden müssten. Wenn diese zwei Bytes nich stimmen, verhält sich Easy wie ein Taubstummer.

Muss wohl ein barockes checksum sein, oder irgend ein Schlüssel.

Ich jedenfalls, kann es nicht knacken :'(

Gruss

Peter
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am Mai 27, 2013, 20:51:44 Nachmittag
 :) Okay, die letzten 2 Bytes der Übertragung sind tatsächlich ein CRC-16 Prüfwert, und zwar ziemlich ähnlich erzeugt wie der MODBUS CRC (nur mit 0xa200 als "initial value") <---- FALSCH (siehe nächsten Beitrag!)
Jetzt müsste man nur noch schlau genug sein, um solche Schlüssel selber zu generieren...  :-\

Ich mach mich mal schlau.

Wenn jemand helfen will ... http://de.wikipedia.org/wiki/Zyklische_Redundanzpr%C3%BCfung

Gruss,

Peter


P.S.: Lieber Admin: Das Thema hat sich wieder einmal sehr von dem Ursprungs-Thread entfernt. Vielleicht könnte man ja uns Bastlern irgendwo ein Thema "Raspberry Pi (Linux) und Easy Kommunikation" stiften.

Des Weiteren wäre es mir lieb zu wissen, ob man solche Sachen hier überhaupt besprechen darf, oder  :-X ob es unerwünscht ist.
Titel: Re:Raspberry Pi + Easy
Beitrag von: Spellbreaker am Mai 29, 2013, 13:40:59 Nachmittag
Moin!

ich benutze dazu entsprechende boost Library:

boost::crc_optimal<16, 0x8005, 0,0,true,true> crc;

Und dann kann man den CRC Bilden wie man möchte. Z.B. jedes Byte einzeln:

crc.process_byte(byte);

Die Summe erhält man dann folgendermaßen:

crc.checksum();



Lg,

Spellbreaker
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am Mai 29, 2013, 21:36:34 Nachmittag
Hi Spellbreaker!

danke für den Tipp. Es bestätigt unter Anderem, dass ich wieder mal falsch lag und alles viel komplizierter scheint als es ist.

In meiner vorherigen Nachricht habe ich ein falsches Algorithmus angewandt.

Ich sagte es wäre ein abgewandeltes Modbus CRC (jedoch mit 0xA200 als Anfangswert)

Das funktioniert zwar, ist aber eine dumme "Verkomplizierung" des Ganzen.

Greg Cook (http://regregex.bbcmicro.net/) klärte mich großzügigerweise auf:

Man muss nur das erste Byte des Pakets aus der Berechnung weglassen und ein stinknormales standard Algorithmus verwenden : ARC (CRC-16, CRC-IBM, CRC-16/ARC, CRC-16/LHA)

Das erste Byte ist bei der Easy nur ein Header (0x45 "E" wenn der Host schreibt, 0x65 "e" wenn Easy schreibt)

Dann funktioniert auch Dein Beispiel bei mir  :)

Vielen Dank nochmal!

Und frohes Schaffen!

Peter

P.S.: von Greg Cook stammt auch die Liste der parametrisierten CRC Algorithmen (http://reveng.sourceforge.net/crc-catalogue/all.htm)
und das RevEng  (http://reveng.sourceforge.net/) CRC multi-tool
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am Mai 30, 2013, 15:34:29 Nachmittag
Ich hab mir da ein flinkes, tabellenbasiertes CRC-16 Programm aus dem Internet umgeschrieben.

Die Bytes des CRC sind leider vertauscht, ich muss später aber sowieso ein bisschen struct.jonglieren, allso bleibt es vorerst so (es sei denn, jemand weiss und sagt  was ich falsch gemacht habe).

# as seen on http://www.digi.com/wiki/developer/index.php/Python_CRC16_Modbus_DF1
# shortened functionality for ease of use : just call getCRC(sting)


table = (
    0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
    0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
    0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
    0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
    0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
    0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
    0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
    0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
    0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
    0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
    0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
    0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
    0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
    0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
    0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
    0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
    0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
    0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
    0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
    0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
    0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
    0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
    0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
    0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
    0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
    0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
    0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
    0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
    0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 )

def getCRC( st ):

    crc = 0x0000

    for ch in st:
       
        crc = (crc >> 8) ^ table[(crc ^ ord(ch)) & 0xFF]

    return crc

Gruß,

Peter
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am Juni 22, 2013, 20:55:55 Nachmittag
Versuchsaufbau:

Easy822-DC-TC
Easy800 USB-CAB
Raspberry Pi mit Python und PySerial Modul



# raspi_com is a script providing serial communication between Raspberry Pi and Easy800 devices via USB-CAB
#
# raspi_com needs pySerial to be previously installed -> http://pyserial.sourceforge.net/pyserial.html
#
# Since this code is Python, it should be portable to other plattforms, but has just been written
# and tested on Raspberry Pi's ARM architecture under Raspbian (a subset of Debian Wheezy)
#
# (c) 2013 Peter Sommer ---------- Dilettanten Ole! ------------ <peter at 3d-check dot com> ---------------
#
# -- This code is free software subject to the GNU General Public License <http://www.gnu.org/licenses/>----
#
# WARNING :
#
# The PLC or it's program MUST restrain or reject received data whenever they don't match process-safe values
#
# The PLC or it's program MUST take care of the process security, being allways and anytime able to deny or
# stop the execution of unsafe actions and undo unsafe process-states triggered by this software
#
# USE ON YOUR OWN RISK
#-----------------------------------------------------------------------------------------------------------

import sys
import struct
import serial
import subprocess
import time

# ----------------------------------------- driver ----------------------------------------------------------
# The cp210x driver is included in recent Linux distributions and just needs --------------------------------
# our USB-Serial bridge's vendor and product ID notifyed to the cp210x driver -------------------------------
# Thanks and free beer plenty for Jon at http://www.ha19.no/usb/ --------------------------------------------

subprocess.Popen('echo 188a 3001 > /sys/bus/usb-serial/drivers/cp210x/new_id',shell=True)

# --------------------------------------------------- ttyUSB port usage -------------------------------------
# -- pySerial encapsulates the access for the serial port -- http://pyserial.sourceforge.net/pyserial.html --
# -----------------------------------------------------------------------------------------------------------

   
def open_port( _name='/dev/ttyUSB0' , _baudrate=9600, _timeout=1 ):

    global o_serial
    global urb

    try:

        o_serial = serial.Serial(_name, baudrate = _baudrate, timeout = _timeout) # create and open serial port
       
        test_mesg = (69,7,0,0,1,0,80,119)               # ---- test the port
        test_mesg = struct.pack('<5BHBB', *test_mesg)
        req=o_serial.write(test_mesg)
        res=o_serial.read(8)

        i_mesg = struct.unpack('<c7B',res)

        in_crc = i_mesg[6:]                             # ---- validate PLC response by CRC16

        in_payload = i_mesg[1:6]

        c_data = struct.pack('<5B',*in_payload)
       
        chk_crc = getCRC(c_data)
       
        if chk_crc == in_crc:
           
            return 0                                    # ---- success: communication ok ---------------- >>>

        else:

            return 1                                    # ---- communication is messy (wrong settings?)
   
    except:

        return 2                                        # ---- no succes creating port
       
def close_port():


    try:
       
        o_serial.close()
        return 0                                        # ---- success
   
    except:

        return 3                                        # ---- no such port
   
       
def write_port(outData):

    try:

        if o_serial.inWaiting() > 0:
           
            urb.append(o_serial.read(o_serial.inWaiting())) # --- flush unrequested data to urb
           
        o_serial.write(outData)

        return listen_port()                                # --- go wait for data

    except:

        return 4                                            # --- no port?

urb = [] # ---- buffer for unrequested data
   
def listen_port():

    try:

        cnt = 0
       
        while cnt < 50 :

            data_len=o_serial.inWaiting()
           
            if data_len > 0:                   
               
                in_header = o_serial.read(1)    # --- get header

                # -------------------------------------- REQUESTED DEVICE TO HOST -------------

                if in_header == 'e':        # --- header from device = response on host request

                    pl_len = o_serial.inWaiting()   
                    in_data = o_serial.read(pl_len)                 
                   
                    in_data = struct.unpack('<'+str(pl_len)+'B',in_data)
                   
                    in_data = list(int(val) for val in in_data)
                   
                    msg_len = in_data[0]            # ---- payload length announced by device
                   
                    if len(in_data)-1 == msg_len:   # ---- if true, guess transfer is completed

                        msg_crc_1 = in_data.pop()   # ---- check data integrity by CRC16
                        msg_crc_2 = in_data.pop()                   

                        c_payload = struct.pack('<'+str(len(in_data))+'B', *in_data)
                        crc = getCRC(c_payload)
                       
                        if msg_crc_1 == crc[1] and msg_crc_2 == crc[0]:   #  data is good!
                           
                            return in_data                      # --- return validated data -->>>
                           
                       
                        else:

                            return 5                            # --- data was a mess

                    else:                                       
                            return 6                            # --- data wrong length
                       
                           

                # -------------------------------------- UNREQUESTED DEVICE TO HOST -------------
               
                else:

                     urb.append(in_header+o_serial.readline())

                     while o_serial.inWaiting() > 0:
                         
                         urb.append(o_serial.readline())        # flush unrequested data to urb
                     
                     return 7                                   # just had unrequested stuff
                   
            else:

                time.sleep(.1)
                cnt=cnt+1

        return 8                                                # ---- function timed out

    except:

        return 9                                    # ---- port is closed or does not exist

# --------------------------------------------------------------------------------------------------   
# ----      plc_item objects provide easy read and write access                                 ----
# ----      they build the "front end" of raspi_com                                             ----
# --------------------------------------------------------------------------------------------------

# ----      dictionaries used for message encoding/decoding (kept public allow edit during runtime)

d_write= {'M':(4,1,'B'),'MB':(10,1,'B'),'MW':(10,2,'H'),'MD':(10,4,'i')} #(type,indx-mult,width)

d_read = {'QA':(9,0,'H'),'IA':(8,0,'4H'),'I':(0,0,'H'),'Q':(1,0,'H'),'M':(4,1,'B'),
          'MB':(10,1,'32B'), 'MW':(10,2,'16H'),'MD':(10,4,'8i')}         #(type,indx-mult, fmt)

# --------- create plc_item instances using this sintax: -------------------------------------------
#                                                                                               ----
#           object = plc_item(location as int, item as string, index as int)                    ----
#                                                                                               ----
# --------------------------------------------------------------------------------------------------

class plc_item:

    def __init__(self, location=0, item_type='Q', index=0):

        self.error = None
        self.timestamp = 0
        self.is_writeable = False
       
        try:
           
            self.location = int(location)

            if d_read.has_key(item_type):
               
                self.item_type = item_type

            else:

                return   # --- unknown PLC item type
       
            self.index = int(index)-1
       
            self.msg_h = [self.location,d_read[self.item_type][0],self.index*d_read[self.item_type][1]]

            self.is_writeable = d_write.has_key(item_type)

            self.error = 0
           
        except:

            return   # --- error creating plc_item
       
    def set_value(self, value):

        if self.is_writeable == True:

            try:
               
                data = struct.pack(d_write[self.item_type][2],value)
                data = struct.unpack(str(d_write[self.item_type][1])+'B',data)
                o_mesg = [self.location,d_write[self.item_type][0],self.index*d_write[self.item_type][1], data]

                resp = write_object(*o_mesg)

                try:

                    resp.pop(0)
                    err_b_1 = resp.pop(0)
                    err_b_2 = resp.pop(0)

                    if err_b_1+err_b_2 == 0:

                        return 0    # --------- success ----- >

                    else:

                        self.error=(err_b_1,err_b_2,resp.pop(0))
                       
                        return 10  # -------- device reported error to be read from self.error

                except:

                     return resp # ------ internal error code (int)
                   
            except:

                return 11  # wrong data ?

        else:

            return 12 # --- plc_item is not writeable
       
   
    def get_value(self):

        if self.error != None :

            resp = read_object(*self.msg_h)
           
            try:
               
                resp.pop(0)
                err_b_1 = resp.pop(0)
                err_b_2 = resp.pop(0)
               
                if err_b_1+err_b_2 == 0:

                    c_mesg = struct.pack(str(len(resp))+'B',*resp)
                    o_mesg = struct.unpack(d_read[self.item_type][2],c_mesg)
           
                    self.values = o_mesg
                    self.error = ()
                    self.timestamp = time.clock()
                   
                    return self.values  # ----- success (data as tuple)

                else:

                    self.error = resp.pop(0)
                   
                    return 13  #---- device reported error to be read from self.error

            except:

                return resp # ----- internal error code

        else:

            return 14 # ---- this plc_item is not working

   
# ------------------------------------------------ message encoding -------------------------------
# -------------------------------------------------------------------------------------------------
# -------------------------------------------------------------------------------------------------

def write_object(B_net_id,B_object,H_index,data): # ----- request write to device memory
   
    try:

        a_data = [int(val) for val in data]
   
        o_msg = [len(a_data)+7, 32, B_net_id, B_object, H_index]+a_data

        c_msg = struct.pack('<4BH'+str(len(a_data))+'B', *o_msg)

    except:

        return 15 # ---- wrong data

    crc = getCRC(c_msg)

    o_msg.insert(0,0x45) # --- header ('E')
    o_msg.append(crc[0]) # --- CRC-16 byte 1
    o_msg.append(crc[1]) # --- CRC-16 byte 0
   
    c_msg = struct.pack('<5BH'+str(2+len(a_data))+'B',*o_msg)

    return write_port(c_msg)    # --- wait for success ------------------------------------------->


def read_object(B_net_id,B_object,H_index):       # ----- request data from device memory

    try:
       
        o_msg = [7, 0, B_net_id, B_object, H_index]
       
        c_msg = struct.pack('<4BH', *o_msg)

    except:

        return 16 # ---- wrong data

    crc = getCRC(c_msg)

    o_msg.insert(0,0x45)  # --- header ('E')
    o_msg.append(crc[0])  # --- CRC-16 byte 1   
    o_msg.append(crc[1])  # --- CRC-16 byte 0

    c_msg = struct.pack('<5BHBB',*o_msg)

    return write_port(c_msg)    # --- wait for data ----------------------------------------------->

# --------------------------------------------------------------------------------------------------
# ------  methods dealing with unrequested device to host messages                              ----
# --------------------------------------------------------------------------------------------------
# ------  flush_data set to False performs a conservative dump

# --------------------------------------------------------- read one item from urb -----------------

def pop_urb(flush_data = True, offset=0):

    global urb

    if len(urb) > offset+1:

        if flush_data:
           
            return urb.pop(offset)        # - returns one line as string and deletes it from the list

        else:

            return urb[offset]            # - just returns one line as string
    else:
       
        return ''

# -------------------------------------------------------------- read all data from urb -------------
   
def dump_urb(flush_data = True):
   
    global urb
   
    ret = urb

    if flush_data:
       
        urb=[]     
   
    return ret                              # - returns urb's data as a list



#---------------------------------------------------- CRC ------------------------------------------------
# Table-based CRC-16 calculation from http://www.digi.com/wiki/developer/index.php/Python_CRC16_Modbus_DF1
# shortened functionality for ease of use in our case, and messy byte juggling added by needs ------------
# Lots of thanks and plenty of gallons free beer go to Greg Cook, for his tool "crc revEng" + advise -----
# http://regregex.bbcmicro.net ---------------------------------------------------------------------------
# --------------------------------------------------------------------------------------------------------


def getCRC( st ):

    crc16_table = (
        0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
        0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
        0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
        0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
        0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
        0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
        0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
        0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
        0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
        0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
        0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
        0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
        0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
        0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
        0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
        0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
        0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
        0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
        0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
        0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
        0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
        0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
        0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
        0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
        0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
        0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
        0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
        0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
        0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
        0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
        0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
        0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 )


    crc = 0x0000
   
    for ch in st:
       
        crc = (crc >> 8) ^ crc16_table[(crc ^ ord(ch)) & 0xFF]
       
    crc = struct.pack('<H',crc)
    crc = struct.unpack('<BB',crc)
         
    return crc
 
# ------------------------------------------------------------------------------------------------ END



Zusätzlich braucht es das PySerial Modul.

So wird es am einfachsten benutzt :

Man kreiert beliebige Instanzen von plc_item, die dann die Methoden set_value(data) und get_value() zur verfügung stellen.

o_item = plc_item(net_id , type, index)

net_id ist 1 byte Integer
type ist String
index ist 2 byte Integer

Implementiert sind folgende "typen":

M = Merker Bit / Index 1 bis 96 / set_value 1 Bit (0 oder 1) / get_value 1 Bit (0 oder 1)

MB = Merker Byte / Index 1 bis 384 / set_value 1 Byte (0 bis 255) / get_value 32 byte

MW = Merker Wort / Index 1 bis 192 / set_value 1 Word (0 bis 65535) / get_value 16 Word

MD = Merker Doppelwort / Index 1 bis 96 / set_value 1 DWord (+/- 2147483646) / get_value 8 DWord

Q = Ausgänge / kein Index / kein Schreibzugriff / get_value 1 Word

QA = Analogausgang / kein Index / kein Schreibzugriff / get_value 1 Word

IA = Analogeingänge / kein Index / kein Schreibzugriff / get_value 4 Word

I = Digitaleingänge / kein Index / kein Schreibzugriff / get_value 1 Word


Zu mehr war ich nicht in der Lage...  ::)


get_value() gibt bei Erfolg ein Tuple zurück, mit den Werten ab Index.
 
Beim lesen von MB,MW und MD bekommt man immer 32 Byte Daten zurück (ab Index).

Ein kleines Beispiel aus der IDLE Konsole:


>>> open_port()
0
>>> M1 = plc_item(0,'M',1)
>>> M1.set_value(1)
[5,0,0,0]    <-------------------- die Nullen hinter der 5 bedeuten Erfolg
>>> M1.get_value()
(1,)
>>> MD1 = plc_item(0,'MD',1)
>>> MD1.set_value(-12345)
[5,0,0,0]
>>> MD1.get_value()
(-12345,0,0,0,0,0,0,0)
>>>close_port()
0


Übrigens: wenn jemand den Baustein "Serielles Protokoll" (LS) in sein Easy-Projekt einbaut, kann die Easy ungefragt auf die Serielle Schnittstelle schreiben.

Bei plc_item.set_value() und plc_item.get_value() werden diese "ungefragten" Daten, sollten sie Anliegen, erst einmal ausgelesen und in der Liste urb gepuffert und können mit pop_urb() und dump_urb() danach ausgelesen werden.

Möglicher Einsatz : Data-Logging

Vielleicht hilft es jemanden.

Gruß,

Peter
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am Juni 30, 2013, 11:52:07 Vormittag
 :-\ Ich bin mir nicht sicher, ob plc_item() richtig funktioniert, wenn eine andere Net-ID angesprochen wird als 0 (Lokal).

>>> open_port()
0
>>> M1ID1=plc_item(1,'M',1)
>>> M1ID1.get_value()
(0,) <--- falsch! das ist der Wert von Net-ID 0
>>> M1ID1.set_value(1)
(5,1,0,25) <--- fehlermeldung von Easy

Zwar bekomme ich bei plc_item.set_value() eine Fehlermeldung von Easy zurück, wenn ich einen nicht vorhandenen Teilnehmer ansprechen will, bei plc_item.get_value() bekomme ich aber dann immer die Werte der Net-ID 0 zurück und keine Fehlermeldung.

Kann leider nicht testen wie es mit einem Angeschlossenem Net-Teilnehmer aussehen würde ...

Meine Vermutung war wohl falsch, dass das vierte Byte der Net-ID entspricht.

Gruß,

Peter
Titel: Re:Raspberry Pi + Easy
Beitrag von: arnenrw am Juli 09, 2013, 16:26:46 Nachmittag
es ist das 3 Byte (davon das Low-Byte)
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am Juli 09, 2013, 22:26:03 Nachmittag
Hi Arne,

danke für die Rückmeldung.

Leider habe ich es nicht ganz kapiert...

Die NET-ID steht im Low-Byte des dritten Byte? Kannst Du mir bitte ein Beispiel geben?

Vielen Dank im Voraus!

Peter
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am Dezember 20, 2013, 20:21:22 Nachmittag
Hi Arne,

danke für dein Tip.

Es hat nur ein halbes Jahr gedauert, bis ich es umgesetzt habe  :(

Jetzt meckert es endlich, wenn man versucht einen nicht vorhandenen Teilnehmer anzusprechen/auszulesen ... ich kann aber nicht ausprobieren ob es wirkilch funtzt wenn der Net-Teilnehmer tatsächlich vorhanden ist.

Sollte aber funktionieren.

Gruß und frohe Weihnachten (auch an die Admins ... oder wurden die wegrationalisiert?!)


Peter

P.S:

Anstatt :


o_msg = [len(a_data)+7, 32, B_net_id, B_object, H_index]+a_data


schreibts sich jetzt:





        o_msg = [len(a_data)+7, 32 + B_net_id, 0, B_object, H_index]+a_data


Jetzt ist ein Byte übrig, der fest mit Null belegt wird ... ::)

Das Ergebniss:

# raspy_com is a script providing serial communication between Raspberry Pi and Easy800 devices via USB-CAB
#
# raspy_com needs pySerial to be previously installed -> http://pyserial.sourceforge.net/pyserial.html
#
# Since this code is Python, it should be portable to other plattforms, but has just been written
# and tested on Raspberry Pi's ARM architecture under Raspbian (a subset of Debian Wheezy)
#
# (c) 2013 Peter Sommer ---------- Dilettanten Ole! ------------ <peter at 3d-check dot com> ---------------
#
# -- This code is free software subject to the GNU General Public License <http://www.gnu.org/licenses/>----
#
# WARNING :
#
# The PLC or it's program MUST restrain or reject received data whenever they don't match process-safe values
#
# The PLC or it's program MUST take care of the process security, being allways and anytime able to deny or
# stop the execution of unsafe actions and undo unsafe process-states triggered by this software
#
# USE ON YOUR OWN RISK
#-----------------------------------------------------------------------------------------------------------

import sys
import struct
import serial
import subprocess
import time

# ----------------------------------------- driver ----------------------------------------------------------
# The cp210x driver is included in recent Linux distributions and just needs --------------------------------
# our USB-Serial bridge's vendor and product ID notifyed to the cp210x driver -------------------------------
# Thanks and free beer plenty for Jon at http://www.ha19.no/usb/ --------------------------------------------

subprocess.Popen('echo 188a 3001 > /sys/bus/usb-serial/drivers/cp210x/new_id',shell=True)

# --------------------------------------------------- ttyUSB port usage -------------------------------------
# -- pySerial encapsulates the access for the serial port -- http://pyserial.sourceforge.net/pyserial.html --
# -----------------------------------------------------------------------------------------------------------

    
def open_port( _name='/dev/ttyUSB0' , _baudrate=9600, _timeout=1 ):

    global o_serial
    global urb

    try:

        o_serial = serial.Serial(_name, baudrate = _baudrate, timeout = _timeout) # create and open serial port
        
        test_mesg = (69,7,0,0,1,0,80,119)               # ---- test the port
        test_mesg = struct.pack('<5BHBB', *test_mesg)
        req=o_serial.write(test_mesg)
        res=o_serial.read(8)

        i_mesg = struct.unpack('<c7B',res)

        in_crc = i_mesg[6:]                             # ---- validate PLC response by CRC16

        in_payload = i_mesg[1:6]

        c_data = struct.pack('<5B',*in_payload)
        
        chk_crc = getCRC(c_data)
        
        if chk_crc == in_crc:
            
            return 0                                    # ---- success: communication ok ---------------- >>>

        else:

            return 1                                    # ---- communication is messy (wrong settings?)
    
    except:

        return 2                                        # ---- no succes creating port (check connections)
        
def close_port():


    try:
        
        o_serial.close()
        return 0                                        # ---- success
    
    except:

        return 3                                        # ---- no such port
    
      
def write_port(outData):

    try:

        if o_serial.inWaiting() > 0:
            
            urb.append(o_serial.read(o_serial.inWaiting())) # --- flush unrequested data to urb
            
        o_serial.write(outData)

        return listen_port()                                # --- go wait for data

    except:

        return 4                                            # --- no port?

urb = [] # ---- buffer for unrequested data
    
def listen_port():

    try:

        cnt = 0
        
        while cnt < 50 :

            data_len=o_serial.inWaiting()
            
            if data_len > 0:                    
                
                in_header = o_serial.read(1)    # --- get header

                # -------------------------------------- REQUESTED DEVICE TO HOST -------------

                if in_header == 'e':        # --- header from device = response on host request

                    pl_len = o_serial.inWaiting()  
                    in_data = o_serial.read(pl_len)                
                    
                    in_data = struct.unpack('<'+str(pl_len)+'B',in_data)
                    
                    in_data = list(int(val) for val in in_data)
                    
                    msg_len = in_data[0]            # ---- payload length announced by device
                    
                    if len(in_data)-1 == msg_len:   # ---- if true, guess transfer is completed

                        msg_crc_1 = in_data.pop()   # ---- check data integrity by CRC16
                        msg_crc_2 = in_data.pop()                  

                        c_payload = struct.pack('<'+str(len(in_data))+'B', *in_data)
                        crc = getCRC(c_payload)
                        
                        if msg_crc_1 == crc[1] and msg_crc_2 == crc[0]:   #  data is good!
                            
                            return in_data                      # --- return validated data -->>>
                            
                        
                        else:

                            return 5                            # --- data was a mess

                    else:                                      
                            return 6                            # --- data wrong length
                        
                            

                # -------------------------------------- UNREQUESTED DEVICE TO HOST -------------
                
                else:

                     urb.append(in_header+o_serial.readline())

                     while o_serial.inWaiting() > 0:
                        
                         urb.append(o_serial.readline())        # flush unrequested data to urb
                    
                     return 7                                   # just had unrequested stuff
                  
            else:

                time.sleep(.1)
                cnt=cnt+1

        return 8                                                # ---- function timed out

    except:

        return 9                                    # ---- port is closed or does not exist

# --------------------------------------------------------------------------------------------------    
# ----      plc_item objects provide easy read and write access                                 ----
# ----      they build the "front end" of raspy_com                                             ----
# --------------------------------------------------------------------------------------------------

# ----      dictionaries used for message encoding/decoding (kept public allow edit during runtime)

d_write= {'M':(4,1,'B'),'MB':(10,1,'B'),'MW':(10,2,'H'),'MD':(10,4,'i')} #(type,indx-mult,width)

d_read = {'QA':(9,0,'H'),'IA':(8,0,'4H'),'I':(0,0,'H'),'Q':(1,0,'H'),'M':(4,1,'B'),
          'MB':(10,1,'32B'), 'MW':(10,2,'16H'),'MD':(10,4,'8i')}         #(type,indx-mult, fmt)

# --------- create plc_item instances using this sintax: -------------------------------------------
#                                                                                               ----
#           object = plc_item(location as int, item as string, index as int)                    ----
#                                                                                               ----
# --------------------------------------------------------------------------------------------------

class plc_item:

    def __init__(self, location=0, item_type='Q', index=0):

        self.error = None
        self.timestamp = 0
        self.is_writeable = False
        
        try:
            
            self.location = int(location)

            if d_read.has_key(item_type):
                
                self.item_type = item_type

            else:

                return   # --- unknown PLC item type
        
            self.index = int(index)-1
        
            self.msg_h = [self.location,d_read[self.item_type][0],self.index*d_read[self.item_type][1]]

            self.is_writeable = d_write.has_key(item_type)

            self.error = 0
            
        except:

            return   # --- error creating plc_item
        
    def set_value(self, value):

        if self.is_writeable == True:

            try:
                
                data = struct.pack(d_write[self.item_type][2],value)
                data = struct.unpack(str(d_write[self.item_type][1])+'B',data)
                o_mesg = [self.location,d_write[self.item_type][0],self.index*d_write[self.item_type][1], data]

                resp = write_object(*o_mesg)

                try:

                    resp.pop(0)
                    err_b_1 = resp.pop(0)
                    err_b_2 = resp.pop(0)

                    if err_b_1+err_b_2 == 0:

                        return 0    # --------- success ----- >

                    else:

                        self.error=(err_b_1,err_b_2,resp.pop(0))
                        
                        return 10  # -------- device reported error to be read from self.error

                except:

                     return resp # ------ internal error code (int)
                    
            except:

                return 11  # wrong data ?

        else:

            return 12 # --- plc_item is not writeable
        
    
    def get_value(self):

        if self.error != None :

            resp = read_object(*self.msg_h)
            
            try:
                
                resp.pop(0)
                err_b_1 = resp.pop(0)
                err_b_2 = resp.pop(0)
                
                if err_b_1+err_b_2 == 0:

                    c_mesg = struct.pack(str(len(resp))+'B',*resp)
                    o_mesg = struct.unpack(d_read[self.item_type][2],c_mesg)
            
                    self.values = o_mesg
                    self.error = ()
                    self.timestamp = time.time()
                    
                    return self.values  # ----- success (data as tuple)

                else:

                    self.error = (err_b_1,err_b_2,resp.pop(0))
                    
                    return 13  #---- device reported error to be read from self.error

            except:

                return resp # ----- internal error code

        else:

            return 14 # ---- this plc_item is not working

    
# ------------------------------------------------ message encoding -------------------------------
# -------------------------------------------------------------------------------------------------
# -------------------------------------------------------------------------------------------------

def write_object(B_net_id,B_object,H_index,data): # ----- request write to device memory
    
    try:

        a_data = [int(val) for val in data]
    
        o_msg = [len(a_data)+7, 32 + B_net_id, 0, B_object, H_index]+a_data

        c_msg = struct.pack('<4BH'+str(len(a_data))+'B', *o_msg)

    except:

        return 15 # ---- wrong data

    crc = getCRC(c_msg)

    o_msg.insert(0,0x45) # --- header ('E')
    o_msg.append(crc[0]) # --- CRC-16 byte 1
    o_msg.append(crc[1]) # --- CRC-16 byte 0
    
    c_msg = struct.pack('<5BH'+str(2+len(a_data))+'B',*o_msg)

    return write_port(c_msg)    # --- wait for success ------------------------------------------->


def read_object(B_net_id,B_object,H_index):       # ----- request data from device memory

    try:
        
        o_msg = [7, 0, B_net_id, B_object, H_index]
        
        c_msg = struct.pack('<4BH', *o_msg)

    except:

        return 16 # ---- wrong data

    crc = getCRC(c_msg)

    o_msg.insert(0,0x45)  # --- header ('E')
    o_msg.append(crc[0])  # --- CRC-16 byte 1  
    o_msg.append(crc[1])  # --- CRC-16 byte 0

    c_msg = struct.pack('<5BHBB',*o_msg)

    return write_port(c_msg)    # --- wait for data ----------------------------------------------->

# --------------------------------------------------------------------------------------------------
# ------  methods dealing with unrequested device to host messages                              ----
# --------------------------------------------------------------------------------------------------
# ------  flush_data set to False performs a conservative dump

# --------------------------------------------------------- read one item from urb -----------------

def pop_urb(flush_data = True, offset=0):

    global urb

    if len(urb) > offset+1:

        if flush_data:
            
            return urb.pop(offset)        # - returns one line as string and deletes it from the list

        else:

            return urb[offset]            # - just returns one line as string
    else:
        
        return ''

# -------------------------------------------------------------- read all data from urb -------------
  
def dump_urb(flush_data = True):
    
    global urb
    
    ret = urb

    if flush_data:
        
        urb=[]      
    
    return ret                              # - returns urb's data as a list



#---------------------------------------------------- CRC ------------------------------------------------
# Table-based CRC-16 calculation from http://www.digi.com/wiki/developer/index.php/Python_CRC16_Modbus_DF1
# shortened functionality for ease of use in our case, and messy byte juggling added by needs ------------
# Lots of thanks and plenty of gallons free beer go to Greg Cook, for his tool "crc revEng" + advise -----
# http://regregex.bbcmicro.net ---------------------------------------------------------------------------
# --------------------------------------------------------------------------------------------------------


def getCRC( st ):

    crc16_table = (
        0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
        0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
        0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
        0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
        0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
        0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
        0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
        0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
        0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
        0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
        0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
        0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
        0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
        0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
        0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
        0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
        0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
        0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
        0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
        0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
        0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
        0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
        0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
        0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
        0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
        0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
        0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
        0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
        0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
        0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
        0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
        0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 )


    crc = 0x0000
    
    for ch in st:
        
        crc = (crc >> 8) ^ crc16_table[(crc ^ ord(ch)) & 0xFF]
        
    crc = struct.pack('<H',crc)
    crc = struct.unpack('<BB',crc)
          
    return crc
 
# ------------------------------------------------------------------------------------------------ END
Titel: Re:Raspberry Pi + Easy
Beitrag von: HORR am August 13, 2014, 11:39:02 Vormittag
gibt es zu diesem Thema nichts neues ?
oder hat einer neue Bastelideen
Titel: Re:Raspberry Pi + Easy
Beitrag von: heicar am August 21, 2014, 13:10:10 Nachmittag
So, hab jetzt auch endlich einen Rapsi bestellt. Habe aber zur Kommunikation mit der Easy bisher immer das Serielle Kabel benutzt. Sollte doch auch funktionieren mit dem obigen Progrämmsche. Natürlich das Device etc. im Programm anpassen.

Ich bin mal gespannt....

Gruß Heicar
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am August 25, 2014, 13:48:04 Nachmittag
Viel Glück Heicar, und lass uns wissen, wie das mit dem seriellen Kabel klappt.

Gruß,

Peter
Titel: Re:Raspberry Pi + Easy
Beitrag von: heicar am August 30, 2014, 16:14:55 Nachmittag

blöde Frage noch  - kenne mich mit Python nicht so recht aus.

Wie rufe ich das Script denn nun auf - hast du mal ein kurzes Beispiel ??

Danke dir


----- Nachtrag

Hab jetzt in der Python Console probiert.

Gleich beim open_port() kommt schon als Antwort "2"
Lustiger Weise kann ich aber Merker setzen mit set_value - läuft dann aber in den Timeout (8)

Get_value() läuft in den Timeout (8) - ok wg. Port

Wieso kann ich Merker setzen, wenn doch angeblich der Port nicht richtig initialiesiert ist?

wenn ich ein close_port() ausführe kann ich keine Merker setzen - Port ist also geöffnet -hmm


Ich benutze eine USB auf Seriell Adapter
Bus 001 Device 004: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port


Wie gesagt - Python ist mir komplett neu.... Im Momemt mehr try und ganz viel Error.....
Titel: Re:Raspberry Pi + Easy
Beitrag von: heicar am August 31, 2014, 11:25:43 Vormittag
so,
- habe einen anderen Rechner (Desktop - auch linux) genommen - gleiches Ergebnis
- habe eine andere 800er genommen Netid2 - gleiches Ergebnis
- habe Serielles Baustein auf Netid2 eingebaut - keine Auswirkungen

Hmmm, weiß jetzt nicht weiter. Ich kann Merker setzen - aber keine Chance irgendwas von der Easy zu empfangen.

und nu? Wer hat mal einen Denkanstoß für mich??

Danke Heicar

Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am September 01, 2014, 20:21:27 Nachmittag
Hi Heicar!

Erstmals danke für deine Bemühungen.

Es tut mir leid, dass eine Reaktion auf deine Fragen so spät kommt...

Bist Du Dir sicher, dass die Merker, die Du mit set_value() setzen willst, auch wirklich auf der Easy gesetzt werden?

Die Funktion write_port() hat nämlich keine Möglichkeit zu prüfen, ob die Easy überhaupt etwas empfangen, geschweige denn "verstanden" oder ausgeführt hat. Dies wird erst durch "listen_port()" bewerkstelligt. Dort wird die Antwort der Easy auf unsere write Anweisung erwartet. Wenn nichts kommt, dann wird 8 (timeout) zurückgegeben.

Das wäre wichtig zu wissen...

Auf jeden Fall ist es wichtig, dass erst einmal open_port() "0" als Rückgabewert bringt. Sonst ist irgendwo der Hund drinn.

Wenn Du open_port() ohne Übergabeparameter verwendest, werden die Default-Werte für _name und _baudrate übernommen ('dev/ttyUSB0' und 9600 baud).

Es kann sein, dass eins von beiden nicht stimmt.

Füge mal in die Funktion open_port() eine Zeile direkt über "return 2" eine Zeile mit  "raise" ein.

Dann bekommst Du eine Fehlermeldung... die hilft uns vielleicht weiter.

Viel Glück!

Gruß,

Peter

P.S.: Ich habe das Skript übrigens inzwischen auch auf Windows (Vista 32 und Windows7 64) Maschinen laufen lassen, mit Erfolg (das ist aber nicht unbedingt Sinn der Sache). Jedoch immer mit dem USB-CAB.






 
Titel: Re:Raspberry Pi + Easy
Beitrag von: heicar am September 02, 2014, 17:55:28 Nachmittag
Hallo

erstmal zu der Fehlermeldung nach dem raise

    i_mesg = struct.unpack('<c7B',res)
struct.error: unpack requires a string argument of length 8


Scheint logisch die Fehlermeldung - es kommt wohl auch gar nichts an.

Ich kann definitiv setzen. Ich habe einen Merker über das Programm gesetzt das welcher sonst nicht vom Programm aus gesetzt wird.
Sowohl auf 1 als auf 0 setzten geht.
Ich habe das Kabel zur SPS auf die 3. Easy umgesetzt. Gleiches Problem ich kann den Merker auf Netid 1 setzen, bekomm aber keine Rückmeldung.

Achso - der Merker den ich setzte schaltet eine Lampe die gleich neben mir ist. Also die visuelle Kontrolle ist ok! :-)

Kann es wirklich am Kabel liegen???? Kann ich senden, aber nichts empfangen ist das möglich?????

Die open Port Parameter habe ich auch andere Varianten getestet - dort ging dann nichts.

Wirklich das Kabel????

Hilfe  ???
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am September 02, 2014, 22:38:45 Nachmittag
 :-\ da weiss ich wirklich nicht weiter ...

Den richtigen Linux-Treiber für dein Kabel hast Du ja scheinbar ...

Anbei die neueste Version als Download. Da gibt es eine Funktion scan_baudrates() die versucht mit Geduld eine Verbindung zur Easy herzustellen.

Probier diese Funktion mal aus, ohne vorher open_port() aufzurufen.

Was kommen da für meldungen auf der Konsole?

Danke für deine Hilfe!

Gruß,

Peter
Titel: Re:Raspberry Pi + Easy
Beitrag von: heicar am September 03, 2014, 17:18:11 Nachmittag
Hallo Peter

folgendes erscheint

>>> scan_baudrates()
Trying to connect /dev/ttyUSB0 at 9600 baud
Error 8
Trying to connect /dev/ttyUSB0 at 19200 baud
Error 8
Trying to connect /dev/ttyUSB0 at 38400 baud
Error 8
Trying to connect /dev/ttyUSB0 at 57600 baud
Error 8
1022
>>>


Danke für deine Hilfe

Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am September 03, 2014, 18:33:52 Nachmittag
Hi Heicar ... die Nuss müssen wir doch knacken können ... :-X

In der Funktion listen_port() ist direkt über return 8 die Zeile  time.sleep(.01) mit # auskommentiert.

Lösche mal das # und mal schauen was passiert.

Kannst auch höhere Zeiten eingeben ... meinetwegen time.sleep(.1)

Mal sehen was passiert.

Danke!

Gruß,

Peter
Titel: Re:Raspberry Pi + Easy
Beitrag von: heicar am September 03, 2014, 18:58:40 Nachmittag
Ich hab zu danken Peter,

also erstes Ergebnis mit .01, zweites mit 0.1, drittes mit 1 ist jeweils immer

>>> scan_baudrates()
Trying to connect /dev/ttyUSB0 at 9600 baud
Error 8
Trying to connect /dev/ttyUSB0 at 19200 baud
Error 8
Trying to connect /dev/ttyUSB0 at 38400 baud
Error 8
Trying to connect /dev/ttyUSB0 at 57600 baud
Error 8
1022


?

Gruß Heicar
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am September 03, 2014, 21:19:23 Nachmittag
Da kommt scheinbar überhaupt nichts rüber von der Easy.

Kaum zu glauben, dass die Kommunikation in Richtung Easy klappt aber nichts von dort zurück kommt.

Hast Du in deinem Easy Programm zufälligerweise irgend ein SP Baustein eingebaut (Serielles Protokoll)? Ich glaube damit schon mal Probleme gehabt...

Ansonsten fällt mir nichts mehr ein (bin auch nicht unbedingt ein Experte).

Hast Du dein USB Kabel mal unter Windows an Easy-Soft oder der EasyCom DLL getestet?

Ich werde versuchen ein Abgespecktes Script zu schreiben, das es uns leichter macht das Problem einzugrenzen.

Gruß,

Peter
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am September 03, 2014, 21:33:02 Nachmittag
Versuche mal das hier, bitte:

#

import serial
import time

s =serial.Serial('/dev/ttyUSB0', baudrate = 9600, timeout = 0)

d = '\x45\x08\x20\x00\x04\x08\x00\x01\xCF\x92'

res=s.write(d)

print res

time.sleep(1)

res=s.read(10)

print res.encode('hex')


Das versucht M9 auf "1" zu setzen, und versucht dann die Rückmeldung von Easy zu lesen.

Die richtige Antwort wäre 650500000000cc (65=header, 05=länge ab hier, 00 00 00 = kein Fehler, 00 CC = CRC16 hash)

Danke nochmal!

Gruß,

Peter
Titel: Re:Raspberry Pi + Easy
Beitrag von: heicar am September 04, 2014, 20:03:57 Nachmittag
tja,

das kommt als Ausgabe

10
00

...
Mit Windows und der Easy Soft klappte die Kommunikation bestens

Ich werde wohl in ein neues Kabel investieren müssen...


Danke für deine Hilfe Peter

Gruß Heicar
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am September 04, 2014, 23:26:50 Nachmittag
Hi Heicar,

Wenn dein Kabel unter Easy Soft gut funzt, dann muss ich davon ausgehen, dass es nicht am Kabel liegt, wenn es mit meinem armseligen Skript nicht tut...

Trotzdem ...  ::)

Also die 10 die als erstes erscheint ist kein Wunder, das ist nur die Anzahl an Byte die auf das Port geschrieben worden ist.

Ob diese 10 Byte irgend ein Gerät gelesen hat, das weiss man zu diesem Zeitpunkt noch nicht.

Als Bestätigung für den gelungenen Empfang, würde die Easy aber netterweise eine Antwort auf das (den?) Port schreiben, entweder eine Fehlermeldung, oder eine Erfolgsmeldung.

Sogar bei Passwort geschützter Schnittstelle, würde die Easy zumindest eine komplette Antwort schicken (komplett ist, nach meinem Wissensstand : ein header Byte, noch ein Byte mit der Anzahl an darauf folgenden bytes, zwei oder mehr weitere Bytes mit information und zwei abschließende Bytes mit dem CRC16 hash)

Wenn dein M9 tatsächlich auf der Easy gesetzt wurde, dann gehe ich davon aus, dass die Easy die Botschaft empfangen, verstanden und ausgeführt hat, und dementsprechend eine Erfolgsmeldung zurückschickt, die zumindest eine Handvoll Bytes beinhaltet.

Unter bestimmten Umständen (Port wird aderseitig benutzt, Einstellungen stimmen nicht, hash stimmt nicht, timeout, etc...) gibt s.read() - auf meinem Windows Rechner und auf dem Raspy - einen Null-Byte zurück ... sozusagen gar nichts, dargestellt auf der Konsole durch eine leere Zeile.

00 ist jedoch 'etwas', auch wenn es sich nicht danach anhört, ganze 8 bit.

Die beste Nachricht die Du mir geben könntest ist, dass M9 NICHT gesetzt wurde...

Leider fehlt hier Feedback von weiteren, geduldigen, tapferen "Beta-Testern". Das macht die Sache viel schwerer.

Also, danke nochmal, Heicar.

Gruß,

Peter
Titel: Re:Raspberry Pi + Easy
Beitrag von: heicar am September 05, 2014, 06:32:09 Vormittag
Im Grunde funktioniert das Kabel. Es ist aber ja eins mit serieller also SubD9 Buchse. Ich habe diese dann über ein RS232-RJ45 Wandler ins Netz gehängt, damit ich nicht direkt am Schaltschrank sitzen muss wenn ich die Easy programmieren will.
Jetzt habe ich eine USB-Seriell Adapter an dem Raspi angeschlossen und diesen dann direkt mit der Easy verbunden. Ich hatte auch einen zweiten USB-Seriell Adapter getestet - ging auch nicht.

Wenn du mit den HEX Code bitte mit dem Merker 75 umschreiben könntest kann ich direkt sehen ob er gesetzt wird.

Gruß Heicar
Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am September 05, 2014, 19:48:45 Nachmittag
Anbei die codierten strings:

M75 Net ID 0 auf 1 setzen : '\x45\x08\x20\x00\x04\x4a\x00\x01\x6f\x86'
M75 Net ID 0 auf 0 setzen : '\x45\x08\x20\x00\x04\x4a\x00\x00\xae\x46'

M75 Net ID 0 lesen : '\x45\x07\x00\x00\x0a\x09\x00\x27\xe5'

(Das gibt zwar nicht nur M75 zurück, ist aber die verwendete Anfrage)

Viel Glück!!!!  :)

Und schönes Wochenende.

Peter
Titel: Re:Raspberry Pi + Easy
Beitrag von: heicar am September 08, 2014, 19:29:49 Nachmittag
Danke Peter,

so ich kann dich beruhigen. Dein Script funktioniert. Ich habe mir ein EASY USB Kabel geordert. Und siehe da - Es geht damit. Ich kann also Merker setzen und diese dann auch abfragen. Ausgänge abfragen geht auch.
Erste Sahne  :)

Gerad eben hab ich mich ans Logging von ca. 20 Merkern - Problem dann wenn das Logging über dein Script läuft kann ich nichts mehr über das Script schalten.
Ich muss ja immer aktiv die Merker auf den aktuellen Zustand abfragen. Da dauert es ziemlich lange bis wieder der 1. Merker abgefragt wird.  So ist wohl auch keine Zeit "zwischendurch" noch irgendeinen Merker zu setzen. Es müsste also eine zweite unabhängige Instanz auf den USB Port schreiben. Geht sowas? Sonst wird die Latenz von druck auf den Webbutton bis zum Auslösen einer Aktion zu lange - und die Frau schreit das es defekt ist....
Jetzt habe ich ca. eine Latenz von einer Sekunde. Ist das i.O??? Oder kann man was optimieren.

Danke Heicar

Titel: Re:Raspberry Pi + Easy
Beitrag von: Peter_Pig am September 09, 2014, 00:56:41 Vormittag
Hi Heicar,

ich bin spät drann, nach einem 18 Stunden Tag.

Es freut mich, dass es mit dem USB-CAB doch funktioniert  :D

Der Preis dieses Kabels ist aber m.E. unverhältnissmässig hoch, deshalb hätte ich mich gefreut, wenn sich andere Wege finden ließen.

Das bleibt wohl für später offen...

So, nun zu deinen Fragen (ganz kurz, weil müde):

Ich rate Dir davon ab, einzelne Merker(-Bit) abzufragen. Versuche in deinem Easy Programm alle Merker so dicht wie möglich zusammenzuführen (d.h. benachbarte Merker verwenden).

Z.B. kannst Du dann M1 bis M32 mit nur einem Aufruf von MD1.get_value() auslesen. Der 32 bit Integer den du bekommst, braucht dann ein bisschen Dekodierung, um die einzelnen Bits auszulesen, das geht aber relativ einfach.

Am besten ist wenn man solche Aufgaben dem Fernrechner überlässt (z.B. mittels JavaScript), das spart dem Raspy Arbeit, vor allen dingen wenn mehrere Clients auf einmal etwas von ihm wollen.

Dann gibt es noch die Methode get_values() - anstatt get_value() - die gibt dir, mit einer einzigen Abfrage, gleich 32 byte aus dem Speicherbereich zurück...

Es sind noch andere Funktionen verfügbar, die die Sache erleichtern könnten:

Jede plc_item Instanz kann Ihren Wert selbstständig ins Netzwerk schicken, so dass alle Rechner - die auf diesen Port hören - sie empfangen (broadcasting).

Dafür sind die Übergabeparameter bc_port und bias da:

Wenn der vorherige Wert des plc_items sich um mindestens den Wert bias ändert, schickt er automatisch seinen neuen Wert ins Netz, über bc_port.

Der Haken ist: plc_item tut sich erst "updaten" wenn get_value() aufgerufen wird...

Ich habe da einen Socket-Server Script, der auf meinem Raspi als Dienst läuft. Das Skript benutzt die com_lib.py um mit der Easy zu kommunizieren (also com_lib.py in den selben Ordner werfen), und sockets um mit anderen (lokalen oder fernen) Prozessen zu kommunizieren:

#!/usr/bin/env python

# IPC_TO_SERIAL.py  #140416 -------------------------------------------
#
# socketserver for com_lib.py
#----------------------------------------------------------------------

import com_lib as com_lib

import os
import socket
import select
import struct
import serial
import sys
import time
import atexit

time.sleep(10)

res = com_lib.set_device_baudrate(57600)

if res == 0:
    
    print com_lib.o_serial
    com_lib.close_port()


# ------------------------------------------ default plc_items ---------------------------------------

for index in range(1,97):

    exec('M'+str(index)+'=com_lib.plc_item(0,\"M\",'+str(index)+')')
    exec('MB'+str(index)+'=com_lib.plc_item(0,\"MB\",'+str(index)+')')
    exec('MW'+str(index)+'=com_lib.plc_item(0,\"MW\",'+str(index)+')')
    exec('MD'+str(index)+'=com_lib.plc_item(0,\"MD\",'+str(index)+')')
    
for index in range(1,13):

    exec('I'+str(index)+'=com_lib.plc_item(0,\"I\",'+str(index)+')')

for index in range(1,9):

    exec('Q'+str(index)+'=com_lib.plc_item(0,\"Q\",'+str(index)+')')

for index in range(1,5):

    exec('IA'+str(index)+'=com_lib.plc_item(0,\"IA\",'+str(index)+')')

QA = com_lib.plc_item(0,'QA',1)

# -------- subscriptions --------

subscribed_items = []


def subscribe_item(_item,_port,_max_age=1,_bias=0):

    _item.port = _port
    _item.max_age = _max_age
    _item.bias = _bias

    subscribed_items.append(_item)
    
def unsubscribe_item(_item):

    _item.port = None
    
    subscribed_items.remove(_item)

subscribe_item(Q1,54000,.1)
subscribe_item(IA1,54000,1.5,10)
subscribe_item(MD1,54000,2)
subscribe_item(MD89,54000,3)

def get_interfaces():
    
    resp =[]
    
    for item in subscribed_items:

        tmp_item = (item.item_type+str(item.index+1),item.port,item.max_age,item.bias)
        resp.append(tmp_item)

    return resp

        
# ------------------ serial ----

s_name='/dev/ttyUSB0'
s_baudrate=9600
s_timeout=1

def set_serial(_name,_baudrate,_timeout):

    global s_name,s_baudrate,s_timeout
    
    s_name = _name
    s_baudrate = _baudrate
    s_timeout = _timeout
    
# ------------------------- raw socket to serial com -----------------

def write_port(outData):

    try:

        if com_lib.o_serial.inWaiting() > 0:
            
            com_lib.urb.append(com_lib.o_serial.read(com_lib.o_serial.inWaiting())) # --- flush unrequested data to urb
            
        com_lib.o_serial.write(outData)
  
        return listen_port()                                # --- go wait for data

    except:

        return 4                                            # --- no port?

def listen_port():

    try:

        cnt = 0
        
        while cnt < 500 :

            data_len=com_lib.o_serial.inWaiting()

            if data_len > 6: #( ----  smallest message 'e'/len/err_1/err_2/crc_1/crc_2
            
                in_packet = com_lib.o_serial.read(2)

                tupl = struct.unpack('<sB',in_packet)

                if tupl[0] == 'e':
                    
                    pl_len = int(tupl[1])
                    in_packet = in_packet+com_lib.o_serial.read(pl_len)
                    
                    return in_packet

                else:

                    in_packet = in_packet+com_lib.o_serial.read(com_lib.o_serial.inWaiting())
                    return in_packet
                
            else:
                cnt=cnt+1

        return 8                                    # ---- function timed out

    except:

        return 9                                    # ---- tty port is closed or does not exist
    

# ----------------- sockets --------------------------------------
# ----------------------------------------------------------------

# ----------------- socket server --------------------------------

client_objects = []
size = 1024

# setup variables and server sockets (UNIX and INET)

unix_sock = '/tmp/raspy_com'

# clean up for nix

if os.path.exists(unix_sock):

    os.remove(unix_sock)

# server sockets

unix_backlog = 5

tcp_host = None


# ------ get LAN address ----------------------------------

if tcp_host == None:
    
    if os.name != "nt":

        import fcntl

        def get_interface_ip(ifname):

            ts = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            return socket.inet_ntoa(fcntl.ioctl(ts.fileno(), 0x8915, struct.pack('256s',ifname[:15]))[20:24])
            
        
    tcp_host = socket.gethostbyname(socket.gethostname())

    if tcp_host.startswith('127.'):

        interfaces = ['eth0','eth1','eth2','wlan0','wlan1','wifi0','ath0','ath1','ppp0',]

        for ifname in interfaces:

            try:

                tcp_host = get_interface_ip(ifname)
                
                break
            
            except IOError:

                tcp_host = 'localhost'            
                pass
        
# ---------------------------------------------------------

def close_sockets():

    print 'closing sockets'
    
    for socket in client_objects:

        socket.close()

atexit.register(close_sockets)

tcp_port = 50000
tcp_backlog = 5

got_nix_server = False
server_count = 0

try :
    
    unix_server = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
    unix_server.setblocking(0)
    unix_server.bind(unix_sock)
    unix_server.listen(unix_backlog)

    client_objects.append(unix_server)
    server_count = 1
    got_nix_server = True
    print 'Unix Socket Server listening at '+unix_sock

except:

    print str(os.name)+' seems not to implement the AF_UNIX family.'

tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_server.setblocking(0)
tcp_server.bind((tcp_host,tcp_port))
tcp_server.listen(tcp_backlog)

client_objects.append(tcp_server)
server_count = server_count + 1
print 'TCP Socket Server listening at '+str(tcp_host)+':'+str(tcp_port)

com_lib.open_port()

# ------------------------ main -----------------------------

running = 1

while running:

    if len(client_objects) > server_count:
        
        startTime = time.time()

        for item in subscribed_items:

            if item.timestamp  < startTime - item.max_age:
                #print 'updating item '+item.item_type+str(item.index+1)
                res = item.get_value()

    input_ready,output_ready,in_error = select.select(client_objects,[],client_objects,.01)

    for rc in input_ready:

        if rc == unix_server:

            client,address = unix_server.accept()
            client_objects.append(client)
            
            if com_lib.o_serial == None:

                res = com_lib.open_port()

            client.send(str(len(client_objects)-2))
            print 'new NIX client '+str(len(client_objects)-2)+' connected to socket '+unix_sock
            
        elif rc == tcp_server:
            
            client,address = tcp_server.accept()
            client_objects.append(client)

            if com_lib.o_serial == None:

                res = com_lib.open_port()
                
            client.send(str(len(client_objects)-2))
            print 'new TCP client #'+str(len(client_objects)-2)+' connected by '+str(address)
            
        else:

            try:
                
                sock_type = rc.family
                sock_address = rc.getpeername()
                
                data = rc.recv(size)

            except:

                data = False

            if data:

                if data[0] == 'E':
                    
                    res = write_port(data)
                    rc.send(str(res))

                else:
                    
                    try:
                        
                        exec('res='+data)
                        rc.send(str(res))

                    except:
                        
                        rc.send('?')
                        
            else:

                rc.close()
                client_objects.remove(rc)
                
                if len(client_objects) <= server_count:
                    
                       print 'nobody connected... closing serial port'
                       com_lib.close_port()


    for rc in in_error:                    

        rc.close()
        client_objects.remove(rc)


Dieses Skript Instanziert am Anfang alle M, MB, MD, Q, A die auf einer 822er zur Verfügung stehen.

Später werden, nmittels subscribe_item() einige davon mit einem Port, einem bias und einem max_age (maximales alter) versehen, so dass sie automatisch geupdated werden (fürchterliches wort).

Es ist heute zu spät um das zu erklären ... (gääähhn...) aber vielleicht kannst Du reinschauen, es anpassen und mit rumspielen.

Ich verspreche mehr information demnächst...  ;)

Ach so, ein einfacher Client für die broadcast Pakete:


# -------- udp broadcast receiver ------

MY_PORT = 54000

import sys
from socket import *

s = socket(AF_INET,SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR,1)
s.bind(('',MY_PORT))

while 1:

    data,wherefrom = s.recvfrom(1500,0)
    print data,wherefrom


Gute Nacht + und vielen Dank für deine Geduld!

Gruß,

Peter
Titel: Antw:Raspberry Pi + Easy
Beitrag von: jopebe am August 02, 2016, 19:25:42 Nachmittag
Lang lang ist es her!
Gibt es ein Happy-End?
Oder ist die Sache im Sande verlaufen?
Es wäre schön, wenn EasyNet Anschluss an andere Systeme fände; der Pi wäre ein guter Anfang.
jopebe
Titel: Antw:Raspberry Pi + Easy
Beitrag von: Bastler71Bay am Juni 11, 2022, 08:56:48 Vormittag
Hallo an Alle,

gibt es neue Erkenntnisse in Sachen Serielle Schnittstelle ?
Deren Protokoll ?
Anbindung durch Python?
Oder manuelles Senden(über den Prog-Adapter) auf die Schnittstelle?

CU-Martin
Titel: Antw:Raspberry Pi + Easy
Beitrag von: Bastler71Bay am September 17, 2022, 18:28:59 Nachmittag
Ich brauche die com_lib.py .Das Thema ist fast 8 Jahre tot.Ich möchte mich trotzdem nochmal damit befassen.

Wer kennt diese com_lib.py ?

Oder kann man das Skript umbauen ?

Danke schon mal.