modul für ein I2C Device auf unterschiedlicher Hardware (two level approach?)

Begonnen von klausw, 07 Januar 2014, 17:25:51

Vorheriges Thema - Nächstes Thema

klausw

Hallo zusammen,

ich schreibe gerade ein Modul um ein I2C IC (LED PWM Treiber) angeschlossen ans Pi in FHEM einzubinden. Das funktioniert auch soweit (ich dimme damit über einen Treiber die Halogenlampen in meiner Vitrine).
Jetzt habe ich noch eine weitere Hardware mit der ich ähnliches machen will: http://www.mobacon.de/wiki/doku.php/de/netzer/index Ein kleines Modul mit Mikrocontroller, das es ermöglicht über TCP/IP direkt auf den internen I2C Bus zuzugreifen.
Jetzt gibt es 2 Probleme, zum einen möchte ich kein zweites Modul schreiben und zum anderen kann es ja auch sein, das ich mehrere I2C ICs anschließen will, das Netzermodul aber nur eine Verbindung akzeptiert.
Wenn ich es richtig verstanden habe ist der two level approach dafür die beste Lösung.
Das ganze würde sich etwas weiter gedacht recht flexibel gestalten lassen, z.B. so:
xx_RPI_I2C, xx_BBB_I2C, xx_Netzer_I2C,... für die Ansteuerung
und:
xx_I2C_PCA9635, xx_I2C_BMP180, ... für die ICs
So ließen sich auch neue Hardwareplattformen schnell integrieren.

Ich habe mit schonmal das CUL modul angeschaut, bin aber nicht schlau draus geworden.
Woher weiss z.B. ein logical device, auf welches physical device es zugreifen muss wenn mehrere vorhanden sind.
Beispiel:
ich habe 2 dieser Netzermodule und das Paspberry mit je einem I2C IC bestückt und möchte diese natürlich auch separat ansprechen können.
Gibt es da einfache Beispielmodule?

Grüße
Klaus

RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

rudolfkoenig

ZitatWoher weiss z.B. ein logical device, auf welches physical device es zugreifen muss wenn mehrere vorhanden sind.

Siehe AssignIoPort(), $hash->{IODev}, IOWrite().

klausw

ah langsam steige ich durch

mit IOWrite() wird dann die WriteFn vom physical ausgeführt?

und umgekehrt?

Wenn ich vom physical was ans logical senden will, nehme ich vermutlich Dispatch()
Aber woher weiss das physical Device (oder eher fhem) an welches logical device die Message geehn soll?
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

justme1968

edit: da hat die hälfte gefehlt.

ja. das geht über dispatch. das globale dispatch findet über Clients und MatchList welche dispatchFn in welchem client device typ dann aufgerufen werden soll. dieses (dein) dispatch ist dann dafür zuständig rauszufinden welches logische device dann gemeint ist. die meisten module machen das dann rückwärts über ein $modules{<device type>}{defptr} über das sie den hash zu einer eindeutigen id finden.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Wobei man inzwischen auf Clients verzichten koennte: Dispatch hat mit Clients anfgefangen, aber fuer das automatische Laden von Modulen beim autocreate war mehr Info notwendig, deswegen wurde MatchList eingefuehrt. Leider habe ich es versaeumt dabei Clients abzuschaffen. Logische Module muessen ein Match Eintrag haben, um nur passende Module aufzurufen. Auf diesen koennte man wegen MatchList auch verzichten.

justme1968

ohne die Clients funktioniert aber umgekehrt das AssignIoPort nicht.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Klar, "koennte" bedeutet auch nur, dass man dazu fhem.pl anpassen muesste. Solange sind Client, MatchList & Match alle notwendig.

klausw

Zitat von: justme1968 am 08 Januar 2014, 18:33:52
edit: da hat die hälfte gefehlt.

ja. das geht über dispatch. das globale dispatch findet über Clients und MatchList welche dispatchFn in welchem client device typ dann aufgerufen werden soll. dieses (dein) dispatch ist dann dafür zuständig rauszufinden welches logische device dann gemeint ist. die meisten module machen das dann rückwärts über ein $modules{<device type>}{defptr} über das sie den hash zu einer eindeutigen id finden.

vielen Dank schonmal, ich muss trotzdem nochmal nachhaken ;)


  • Also ruft der gobale dipatch alle clients auf, die laut MatchList bzw. Clients infrage kommen?
  • Kann diese dispatchFn im client auch eine ParseFn sein (z.B. FS20_Parse im 10_FS20.pm Modul)?
  • Mit $modules{FS20}{defptr}{$code} bekommt das modul aber nur raus, ob es gemeint ist, wenn im globalen dispatch auch ein entsprechender $code mit drin ist?

Ich möchte das ganze gern mit I2C Befehlen machen (also die Botschaften zwischen physikalischem und logischem modul).
z.B. eine den Inhalt eines Registers von einem I2C IC lesen. Beim senden des requests ist die Adresse des IC's in der Botschaft (die auch dem $code entsprechen könnte) enthalten.
Das Problem aber ist, das in der Antwort nicht mehr die Adresse des I2C IC's drinsteckt. Das heisst wenn mehrere clients definiert sind dann klappt die Zuordnung nicht mehr.
Das heisst doch, ich müsste es irgendwie sequentiell machen?


RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

justme1968

1. es ruft alle clients der reihe nach auf bis der erste etwas zurück gibt

2. es muss natürlich parseFn heissen

3. das defptr wird nur innerhalb des moduls verwendet. du musst irgendetwas verwenden das im define bekannt ist und das in der
parseFn anhand der antwort abgeleitet werden kann.

wenn es keine eindeutige zuordnung zwischen antwort und device gibt du aber sicher stellen kannst das die antworten ohne ausnahme in der gleichen reihenfolge wie die kommandos kommen kannst du versuchen es darüber zu lösen. also die die reihenfolge in einem fifo merken und in parse auslesen.

wenn das nicht klappt fällt mir gerade nichts ein wie es mit mehreren clients pro physikalischem device gehen kann.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

klausw

Bin zwar noch nicht so weit, aber falls du diese Anpassung vornimmst. Wie bekomme ich diese Veränderung mit?
Zitat von: rudolfkoenig am 08 Januar 2014, 19:24:47
Klar, "koennte" bedeutet auch nur, dass man dazu fhem.pl anpassen muesste. Solange sind Client, MatchList & Match alle notwendig.
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

rudolfkoenig

1. Das ist ganz unten auf der TODO (wenn ueberhaupt)
2. Ich wuerde es hier posten
3. Es wuerde ja weiter funktionieren, nur Client und Match waere irrelevant.

klausw

ich habe mit einfach die CUL und FS20 Module hergenommen und auf der Basis begonnen.

und wieder ein paar Fragen bzw. Gedanken:

  • an die ParseFn wird der $hash vom physical übergeben und daher benötige ich defptr um die ensprechenden logical rauszubekommen?
  • ich würde auch  das I2C read in der WriteFn des physical machen
    also mit IOWrite übergeben, ob ich auf dem I2C lesen oder schreiben möchte und im fall von lesen ein DevIo_SimpleWrite mit einem DevIo_SimpleRead kombinieren. So habe ich immer die passende Antwort zum Befehl und kann in den Dispatch die passende Id für defptr reinpacken.
    Ist das so akzeptabel?
  • Einen Sendepuffer kann ich auch noch anlegen, aber ich sehe im Moment keinen Sinn darin, oder maximal darin, den letzten Befehl pro logical Device zu speichern
  • Die Read_Fn benötige ich eigentlich nicht, da über den I2C nichts ohne Anforderung empfangen wird.
    Kann ich das dann einfach weglassen, oder macht eine Umleitung ins Log Sinn, um Fehler besser zu erkennen?
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

rudolfkoenig

1. an ParseFn werden die (vom ReadFn) gelesenen Daten uebergegeben. ParseFn erzeugt mit den update*Readings Funktionen die Events/Readings, und liefert den Namen der betroffenen logischen Geraete zurueck.
2. das ist schlecht, weil solange FHEM blockiert wird. Sowas stoert viele enorm.
4. ReadFn wird vom gloabalen select aufgerufen, sie liest die Daten und ruft Dispatch() auf, falls ein Paket komplett ist. Dispatch filtert doppelte Nachrichten, sucht den passenden logischen Device (und laedt das Modul, falls es noch nicht geladen ist), ruft dessen ParseFn auf, und triggert die Events.


klausw

Zitat von: rudolfkoenig am 10 Januar 2014, 14:56:19
2. das ist schlecht, weil solange FHEM blockiert wird. Sowas stoert viele enorm.
Die Antwortzeit vom I2C liegt im ms Bereich. Kann das problematisch werden?
Für ungültige Befehle könnte ich ja einen timeout einbauen.

Die 2. Variante währe ein Sendepuffer.

  • IOWrite übergibt daten und info ob i2cread oder i2cwrite
  • WriteFn schreibt es in einen Sendepuffer
  • WriteFn startet das schreiben aus dem Sendepuffer wenn der Sendepuffer durch ReadFn freigegeben
  • Sendepuffer prüft ob die Botschaft ein read request ist
  • wenn nein senden und nächste Botschaft prüfen
    wenn ja senden, die I2C Adresse aus der Botschaft für die ReadFn lesbar speichern und keine weiteren Botschaften senden
  • ReadFn holt sich wenn was reinkommt diese I2C adresse  und schickt sie zusammen mit den empfangenen Daten über Dispatch raus
  • ReadFn gibt den Sendepuffer wieder frei
  • wenn keine Antwort kommt muss es einen Timeout geben
Es sollte eigentlich keine Nachricht kommen, für die nicht schon das Modul geladen ist. Der I2C arbeitet als Slave und sendet nix von sich aus.
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

klausw

mit dem sendepuffer funktioniert es ganz gut

jetzt habe ich eine weitere Hürde:
wenn ich z.B. ein I2C IC mit beispielsweise 16 GPIOs habe möchte ich ja für jeden GPiO einen eigenen define machen. Bisher nutze ich nur die I2C Adresse um in der ParseFn über defptr das passende Modul zu finden.
Wenn ich allerdings für alle 16 GPIOs ein define machen, dann würden sich alle angesprochen fühlen.
Das hätte den evtl. den Vorteil, das Einstellungen, die für mehrere GPIOs gelten auch an alle weitergegeben werden.

  • funktioniert das überhaupt, wenn mehrere definierte Module die gleiche defptr haben?
  • wie könnte ich für unterschiedliche defptr "Ids" erzeugen? Den namen aus dem define zu nehmen habe ich testweise probiert, erscheint mir aber nicht optimal
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280