Hi,
On 02/04/2024 21:54, Sebastian Reinhardt wrote:
Ich steh mal wieder etwas auf dem Schlauch und ich hoffe, dass mir einer von euch den "Schubs" in die richtige Richtung geben kann.
Willkommen auf dem Schlauch. Beim Abstieg bitte Vorsicht, es sind Knoten an unerwarteten Stellen...
Erstmal die Voraussetzungen:
Ich habe an einem PC/PI mehrere I2C-GPIO- Porterweiterungen (MCP23017 und MCP23008) hängen. Die haben 16 bzw. 8 GPIO's und hängen mit verschiedenen Adressen am I2C.
Nun möchte ich diese Bausteine mit C++ über I2C mit entsprechenden Bibliotheken (MCP23017 und MCP23008) direkt ansteuern. Die jeweilige Bezeichnung, Busadresse usw. lese ich aus einer text/csv-DAtei ein und rufe diese Daten aus der Vectorvariable (mcp_elements mit eigener struct) ab. Das funktioniert soweit auch, z.B.:
-------code-------
MCP23017 mcpout1.(atoi(mcp_elements[i_e].busnr.c_str()), atoi(mcp_elements[i_e].busaddr.c_str()));
mcpout1.openI2C();
for ( int i17 = 0; i17 < 16; i17++) {
mcpout1.pinMode(i17, OUTPUT); mcpout1.pinMode(i17, LOW);
}
-------/code-------
Nun muss ich eben für jeden Baustein das Device mit dem Handle/ostream verbinden und benötige eben z.B. "mcpout1", "mcpout2", "mcpout3" usw. Da ich aber nicht sicher weiss, ob immer die gleiche Anzahl von I2C- Bausteinen an den Bus angeschlossen sind, ist diese "Hardcodierung" ungünstig. Um nicht jedes mal das Programm anpassen und neu kompilieren zu müssen, möchte ich die Art (MCP23008/MCP23017), Busadresse, Art der Ports (In-/Outputs) Nummerierung der Ports usw. aus der txt/csv-Datei lesen und das etwas dynamisch behandeln. Das Lesen der Infos klappt schon, aber dann hänge ich....
Ohne zu wissen wie das alles unter der Haube funktioniert ist der Rest dieser Mail eher spekulativ.
Nun die Frage: Kann ich eine Variable (event. einen Vector) erstellen in den ich dann in einer Zeile "Nr", "Streamref", "Portnummerstart", "Portnummerende" speichern kann und dann eben nur diese eine Variable in die anderen Unterprogramme übergeben kann? D.h., kann ich in dieser Variable, und wenn ja wie, die Streamreferenz speichern und übergeben kann. In den Unterprogrammen möchte ich die Variable nach dem Schema "liegt die anzusteuernde Portnummer zwischen "Start" und "Ende", dann ist der Stream/ Referenz zu verwenden benutzen.
Natürlich kannst Du komplexe Strukturen/Klassen mit Referenzen bauen und übergeben. Wir reden hier über C++, da geht sowas.
Profi-Tip: übergib diese Variable als "const MyClass&" an Unterfunktionen - das geht schneller/effizienter (nur ein Pointer auf dem Stack statt einer Kopie der Struktur). Im Vektor bitte als volle Kopie, sonst gibt es schnell Probleme.
Wie müsste die Variable aussehen? Vector mit welcher struct?
Vector ist gut. Struct ist reichlich veraltet - benutz' doch einfach C++! ;-)
Bei sowas baue ich mir gerne kleine Helferklassen. Zum Beispiel:
class McpOutRef { MCP23017 &ref; int start=0,end=0; public: McpOutRef(MCP23017&aref,int astart,int aend):ref(aref),start(astart),end(aend){} McpOutRef(const McpOutRef&)=default; McpOutRef(McpOutRef&&)=default;
McpOutRef& operator=(const McpOutRef&)=default; McpOutRef& operator=(McpOutRef&&)=default;
bool containsPort(int port)const{return astart<=port && aend>=port;}
MCP23017& mcp()const{return ref;}
};
Über containsPort könntest Du abfragen ob der gesuchte Port zu dieser Instanz gehört und über mcp() bekommst Du die Referenz.
Wenn man intern Pointer und extern Referenz benutzt, dann kann man noch etwas mehr "Magie" machen (z.B. saubere "Null-Refs"), aber das führt hier zu weit.
Du kannst Dir auch den Vektor erweitern:
class McpRefVector: public std::vector<McpOutRef> {
bool hasPort(int port){ for ( const auto&elem : *this) if(elem.containsPort(port)) return true; return false; }
McpOutRef& byPort(int port) { .... }
}
Es fehlt noch etwas "Boilerplate" für Constructor, etc. ...
Falls Dein Compiler sich über && oder =default beschwert: -std=c++17 - wir sind ja nicht mehr im finsteren Mittelalter! ;-)
Wäre toll, wenn mich jemand erleuchten könnte.....oder wenigstens den Weg weisen könnte.
Hell genug?
Konrad