Jump to content

Recommended Posts

Geschrieben

Für ein Protokoll ohne speicherfressenden python Brickd gibts sofort meine volle Unterstützung.

Ich hatte gerade angefangen den brickd gegen einen RS485 Konverter  'zu tauschen'.

Schafft Ihr das bis Ende November?

Dann lege ich die Alternative erstmal auf Eis.

 

 

  • Replies 54
  • Created
  • Letzte Antwort

Top Posters In This Topic

Geschrieben

Hallo Borg,

also ich hätte da noch was. Da ich das Protokoll auch wieder implementieren muss ( Perl ) würden folgender Punkt die Arbeit erleichtern

1. length bitte nur von der PayLoad und nicht wieder vom ganzen Packet, beim Senden Konstante drauf, beim Empfangen Konstante wieder runter.

 

mfg

 

Armin

Geschrieben

1. length bitte nur von der PayLoad und nicht wieder vom ganzen Packet, beim Senden Konstante drauf, beim Empfangen Konstante wieder runter.

Mhh, ich weiß nicht. Du musst ja erstmal über den Socket die komplette length empfangen. An der Stelle muss ja eigentlich keine Konstante drauf.

 

also ich denke an sowas wie (Pseudocode)

 

bytes = read(sizeof(Header));
while(len(bytes) != bytes[4]) {
    bytes += read(bytes[4] - len(bytes));
}

Geschrieben

Uns ist da gerade ein Implementierungsdetail aufgefallen, dass wir vorher noch nicht so genau bedacht hatten.

 

Wenn wir das neue Protokoll durchziehen, so wie es bisher gedacht ist, ändert sich das verhalten beim add_device.

 

Im Moment ist es ja so, dass ich mitbekommen wenn ein Brick/Bricklet nicht im System ist während ich add_device aufrufe. Nach der aktuellen Planung des neuen Protokolls wäre es so, dass add_device lediglich intern die UID speichert. D.h. ich würde dort erstmal nicht mitbekommen wenn ein Brick/Bricklet nicht da ist. Das hat aber noch mehr Konsequenzen:

 

Im alten Protokoll wurde an der Stelle z.B. auch überprüft ob das hinzugefügte Bricklet überhaupt zum Objekt passt. Des weiteren wollten wir auf Dauer implementieren, dass dort die FW Version mit der Binding  Version abgeglichen wird, um zu überprüfen ob Funktionen vorhanden sind oder nicht. Das würde natürlich alles wegfallen.

 

Jetzt könnte man an der Stelle hergehen und wieder eine Funktion auf den Bricks implementieren die diese Informationen zurück gibt. Dann wäre an der Stelle wieder alles beim alten.

 

Vorteil:

* Überprüfung ob Brick/Bricklet vorhanden

* Versionsüberprüfung

 

Nachteil:

* Wir haben wieder einen "Zustand" im System.

 

Beispiele für den Nachteil:

* Ich bekomme einen Fehler wenn ein Brick/Bricklet während des Hinzufügens kurzzeitig nicht erreichbar ist.

* Wenn ich z.B. einen RS485 Slave Stack nehme und die Bricks/Bricklets in diesem aktualisiere und dann wieder an den RS485 Bus hänge, hat das Brick/Bricklet Objekt falsche Versionsnummern und neue Funktionalität ist im laufenden Programm nicht vorhanden.

 

Was meint ihr dazu?

Geschrieben

Ich hätte vermutlich AddDevice gänzlich entfernt wenn es möglich wäre.

Alternativ kann man ja auch das Brick mit der IPConnection erzeugen:

new BrickServo("uid", ipcon)

 

Die Device-Klasse könnte ja dann noch so etwas wie eine CheckDevice()-Methode o.ä. anbieten die man unabhängig vom hinzufügen (also potenziell auch regelmäßig/event-basiert) aufrufen kann. Also etwas das den von euch beschriebenen Test durchführt und per Rückgabe (bool/enum) o.ä. den Status meldet. Mögliche Rückgaben (enum-beispiel): OK, VERSION_MISMATCH, NO_RESPONSE

 

andere Frage: Kann man den enumeration-aufruf (also nicht den Callback, sondern die Aufforderung zum Callback) per UID eingrenzen? Also statt zu fragen: "sagt mir alle wer ihr seid" zu rufen "Das Bricklet mit der UID x möge sich bitte im Kinderparadies melden"...

Das wäre eine Möglichkeit die Anwesenheit eines speziellen Bricklets zu prüfen.

Geschrieben

AddDevice wird entfernt, damit fällt dann auch die Versuchung weg ein Device Objekt gleichzeitig mehreren IP Connections hinzuzufügen, was nicht funktioniert.

 

Was CheckDevice() für NO_RESPONSE tun würde kann jetzt schon jeder Getter und in neuen Protokoll auch jeder Setter wenn die R Option gesetzt ist.

 

VERSION_MISMATCH funktioniert so nicht und hätte nur im alten Protokoll auf per-Funktionsbasis gut funktioniert, da der Check Zustand braucht, wenn man nicht vor jedem Aufruf den Brick erst nach seiner Firmwareversion fragen will. Damit ist die angedachte NotSupportedException leider gestorben.

 

Das Problem mit Funktionen, die die Firmware noch nicht kennt, wird jetzt auf dem Brick robust behandelt und unbekannte Funktions ID führen nicht mehr zu einem Absturz des Bricks, sondern werden ignoriert.

 

Für per-Brick "enumerate" wird jedes Device eine GetIdentity Funktion haben, die die gleichen Informationen wie der Enumerate Callback zurückgibt. GetIdentity wird auch die bisherige GetVersion Funktion ersetzen, wobei GetIdentity im Gegensatz zu GetVersion die Informationen nicht zwischenspeichert und dadurch stateless ist.

 

GetIdentity erlaubt es dann auch die Checks die vorher AddDevice gemacht hat zu realisieren:

 

ushort deviceIdentifier;
BrickMaster master = new BrickMaster("UID", ipcon);
master.GetIdentity(..., deviceIdentifier);

if (deviceIdentifier != BrickMaster.DEVICE_IDENTIFIER) {
    // report/handle mismatch
}

 

Die Änderungen sind auch hier beschrieben:

 

http://www.tinkerforge.com/doc/Protocol_20.html#general-api-changes

Geschrieben

Sehr gut.

Aber:

Ich finde es generell schade, dass das Brick nicht mit Error antwortet, wenn man eine unbekannte Function-ID anfragt, sondern dies nur ignoriert.

 

Daher zwei Ideen (sich gegenseitig ausschließend):

1. Neues Flag aus dem Future Use Pool: NotSupported

Das Brick würde zumindest auf R-Pakete mit gesetztem Error- und Notsupported-Flag antworten, wenn es eine Funktion nicht kennt

 

2. Nutzung des Payload bei Error

Bei gesetztem Error-Flag könnte man auch den Payload nutzen, um den Error zu präzisieren. Vorstellbar wäre ein int als error-code, wobei es globale Error-Codes (not-supported) und Brick-spezifische Errorcodes geben kann (z.B. "ungültige Servo-id" oder "ungültiger drehwinkel")

 

Insbesondere wäre damit noch immer ein NotSupported möglich (wodurch kein Timeout bei unbekannten Gettern auftritt, sondern etwas sinnvolles) und der Mehrwert des E-Flag ließe sich weiter steigern (falls bei einem Aufruf mehr als ein Error auftreten kann)

Geschrieben

Es mag den Fall geben, dass man ein "echtes" Paket mit einer nicht-existierenden Funktions ID bekommt. Ich denke aber dass es wahrscheinlicher ist, dass einfach irgendein Programm schrott auf den Port schreibt (absichtlich oder unabsichtlich). Da würde ich dann eigentlich nicht drauf antworten wollen.

 

Zwischen Paketen mit falscher FID und "Schrottpaketen" kann ich aber nicht unterscheiden.

 

Ich bin mir aber auch nicht zu 100% sicher was hier die beste Vorgehensweise wäre.

Geschrieben

Da hast du natürlich recht. Dann würde ich vorschlagen wir machen aus dem einem Error Bit gleich zwei Error-Bits, dann können wir 4 Fehlerzustände zurückgeben:

 

* 0 = OK

* 1 = BAD_PARAMETERS (Index out of range or similar)

* 2 = FUNCTION_NOT_SUPPORTED

* 3 = TODO

Geschrieben

die Konstante ist sizeof(Header).

 

 

head = read(sizeof(header));
payload = read(head[4]);

 

mfg

 

Armin

 

1. length bitte nur von der PayLoad und nicht wieder vom ganzen Packet, beim Senden Konstante drauf, beim Empfangen Konstante wieder runter.

Mhh, ich weiß nicht. Du musst ja erstmal über den Socket die komplette length empfangen. An der Stelle muss ja eigentlich keine Konstante drauf.

 

also ich denke an sowas wie (Pseudocode)

 

bytes = read(sizeof(Header));
while(len(bytes) != bytes[4]) {
    bytes += read(bytes[4] - len(bytes));
}

Geschrieben

Ja, also:

 

bytes = read(sizeof(Header));
while(len(bytes) != bytes[4]) {
    bytes += read(bytes[4] - len(bytes));
}

 

vs

 

bytes = read(sizeof(Header));
while(len(bytes) != (bytes[4] + sizeof(Header))) {
    bytes += read((bytes[4] + sizeof(Header)) - len(bytes));
}

 

:o

Geschrieben

Zu der Neuerung:

Bricks now send the enumeration-added callback on their own after startup.

 

Könnt ihr das noch etwas klarer formulieren? Was bedeutet startup? Warum hilft es, wenn der Callback schon registriert ist, bevor die Verbindung hergestellt wird?

Nach meinem aktuellen Verständnis kann ja der startup des Stacks auch lange vor dem Verbinden der IPConnection liegen.

Geschrieben

Ich hab die Beschreibung erweitert. Es geht darum, dass ein Brick (neu-)gestartet wird und daher noch nicht konfiguriert ist, bzw. durch den Neustart seine Konfiguration verloren hat (z.B. die PWM Einstellung eines Servo Bricks). Damit dieser Zustand robust vom Programm erkannt werden kann sendet der Brick von sich aus ein Enumerate Callback (mit enumerate_type connected), für jede neu erstellte Kommunikationsverbindung wie, USB, TCP/IP über WIFI oder Ethernet Extension usw.

 

Damit das auch bei TCP/IP über WIFI oder Ethernet Extension richtig funktioniert muss die Enumeration Callback Funktion gesetzt sein bevor die Verbindung zum Brick aufgebaut wird, da der Master Brick für jede neu eingehende TCP/IP Verbindung einen Enumerate Callback an diese schicken wird.

 

Dabei kann es passieren das ein Enumerate Callback (mit enumerate_type connected) verschickt wird und es der Brick noch seine Konfiguration hat. Dies tritt z.b. bei einer 2. Verbindung über die WIFI Extension auf. Es kann allerdings nicht passieren, dass der Enumerate Callback nicht gesendet wird obwohl das Programm hätte informiert werden müssen.

Geschrieben
•DISCONNECTED (2): Device is disconnected (only possible for USB connection).

Wie würde das neue Protokoll auf die Situation reagieren, wenn ein Funk-Slave -egal ob via Chibi oder WIFI - abgeschaltet wird, also keine direkte Kabel-Verbindung vorliegt ?

Wird dann auch der Enum-Calbback ausgelöst ? Erkenne ich das Disconnect ?

Muss ich mich als Entw. darum kümmern, das Brick-Objekt am IPConn abzumelden, zu lösen bzw. die Instanz zu destroyen ? Oder wird die Referenz zum IPConn durch das Destroy des Objektes gelöst ?

Was passiert bei Neustart des gleichen wireless Brick-Objektes am Stack ?

Geschrieben

Tatsächlich musst du das Objekt nicht von der IPConnection lösen oder so.

Es wird in dieser Zeit nur nicht großartig reagieren, also weder auf Befehle reagieren (es kommt eine TimeoutException), noch Callbacks liefern.

Ich vermute, dass beim Disconnect keine Enumeration kommt.

Beim Anschließen jedoch solltest du mitbekommen, dass das Device wieder da ist (enumerate mit CONNECTED) und kannst es dementsprechend auch wieder so konfigurieren, dass es einsatzfähig ist.

Geschrieben

Also bleibt in dieser Hinsicht das Verhalten gleich dem alten Protokoll.

Ist es technisch im neuen Protokoll nicht möglich auf das Abschalten eines Funk-Slaves mit Disconnect via Enum-Callback auszulösen ? Oder sieht man die Notwendigkeit nicht, dies in die API einzubauen ?

 

Eine Methode eines nicht mehr erreichbaren Device nur durch eine TimeoutException auflaufen zu lassen ist m.E. zu hart.

Es wäre praktischer, in der Implementation auf ein Disconnect so früh wie möglich reagieren zu können, um den funktionellen Kontext dieses nicht mehr erreichbaren Devices en bloc abzuschalten.

 

Z.B. möchte ich für den User im GUI den Teil dieses Devices komplett disablen, um weitere Funktionsaufrufe zu unterbinden.

 

Nicht immer schaltet man bewußt den Funk-Slave ab, dies kann ganz unerwartet geschehen, weil die Energieversorgung oder die Funkverbindung (zu weite Entf., störende Wände etc.) ausfällt.

Geschrieben

Der brickd kann deshalb robust einen Disconnect erkennen und ein Enumerate dafür auslösen, weil ihm das Betriebssystem sagen kann, dass ein USB Gerät abgezogen wurde.

 

Bei WIFI und Chibi ist das anders: Wenn du da den Brick außer Reichweite bringst oder ihn von der Stromversorgung trennst dann kann er nicht mehr auf Anfragen antworten. Der Brick hat ja auch keine Chance Bescheid zu sagen, dass er disconnected wurde. Bei TCP/IP passiert da dann nichts weiter, dass erlauben würde aus diesem "der Brick antwortet gerade nicht" irgendwie zu erkennen, dass er auch nicht mehr antworten wird. Die TCP/IP Verbindung wurde ja vom Brick aus nicht aktiv geschlossen, also ist sie noch offen, es werden nur im Moment keine Daten gesendet.

 

Das einzige was da bleibt, ist Timeouts als Indikator für eine funktionierende Verbindung zum Brick zu verwenden.

Geschrieben

Es wäre in der Tat möglich, dass die Anwesenheit eines Bricks per ping geprüft wird. Das heißt ich schicke ihm regelmäßig eine Nachricht, dadurch kann ich prüfen ob er noch da ist (also auf Timeout warten).

Das in die Standard API aufzunehmen ist m.E. deswegen keine gute Idee, weil die Anforderungen jeweils unterschiedlich sind.

Der eine möchte die maximale Bandbreite für seine normale Nutzung des Stacks haben, deswegen sollte der Kanal nur selten mit Pings belegt sein. Das führt aber dazu, dass ich nur mit Verzögerung sehe, dass ein Gerät weg ist. Wenn ich das schnell wissen muss, dann geht das nur auf Kosten der Gesamt-Bandbreite.

Anderes Problem: Für dich ist nur der Ausfall des Chibi wahrscheinlich, dir reicht also ein Ping zu einem Chibi-Slave-Gerät. Wenn ich meinen Stack irgendwo aufbaue wo es Vibrationen gibt, dann kann mir auch mal ein Kabel rausrutschen oder sich eine Steckverbindung lösen. Da müsste ich alle Stackteilnehmer pingen.

Deswegen halte ich es nciht für sinnvoll möglich "die" Lösung anzubieten.

 

Das Gute: Man kann sich einen Ping einfach selbst basteln. So wie man ihn braucht. Beispielsweise könntest du dafür die GetIdentity-Funktion nutzen.

Geschrieben
Der brickd kann deshalb robust einen Disconnect erkennen und ein Enumerate dafür auslösen, weil ihm das Betriebssystem sagen kann, dass ein USB Gerät abgezogen wurde.

Ah, ok und danke. Daran hatte ich gar nicht gedacht. Das Ping ist ein guter Gedanke, allerdings wäre es praktischer, das am Device anzusiedeln. Bevor man also die eig. Funktionen aufruft, versichert man sich per Ping ob das Device noch verfügbar ist. Oder per Timer regelmässig und autonom.

Eine Ausfallsicherheit (Watchdog) mittels Monoflop von einem IO müsste auch helfen.

Geschrieben
Bevor man also die eig. Funktionen aufruft, versichert man sich per Ping ob das Device noch verfügbar ist.

 

Das verstehe ich gerade nicht...

Warum ist es besser den Timeout vom Ping zu bekommen als den Timeout vom Function-Call? Der Ping kann immer nur eine Zusatzmaßnahme sein, um den Stack zu überwachen. Man sollte m.E. nicht vor jedem Funktionsruf explizit einen Ping durchführen, weil es unnötig viel kostet ohne einen unmittelbaren Vorteil zu bringen (Den Timeout könntest du auch so erkennen und der Ping schützt dich nicht davor, dass der Funktionsruf doch einen Timeout kriegt).

Geschrieben

Ein Hintergrund-Timer pingt zB. alle 2 Sekunden gegen den Master-Brick eines Slave-Stacks, ob dieser noch verfügbar ist. Wenn nicht, wird der gesamte abhängige Kontext im GUI gesperrt bzw. Disabled um weitere User-Interaktionen zu unterbinden.

 

Die Idee des Pings war doch von Dir, zu welchen Zeitpunkt sollte dieser deiner Vorstellung nach ausgelöst werden ?

 

Alternative sehe ich hier noch über den Monoflop eines IOs der im Slave-Stack integriert ist.

 

Geschrieben

Mir fällt bezgl. Ausfallsicherheit eines Funk-Slaves noch eine andere Möglichkeit ein. Der Master-Brick ist das zentrale Element im Stack, hat aber im Gegensatz zum IMU- oder Stepper-Brick keine Callbacks. (Ausnahme der Enum)

Warum sollte ich von Implementations-Seite den Ping (per Timer) an den Stack senden, per Callback könnte der Master-Brick diesen Ping quasi gleich selber schicken.

Dieser Callback könnte zusätzlich Status Informationen über Signalstärke etc. mitgeben. Im Event-Handler des Callbacks würde immer ein Timer neu gestartet mit einem Interval bei 2 sec. Fällt der Slave aus, würde der Callback ausbleiben und der Timer zuschlagen, um z.B. Funktionen oder Kontexte im Programm abzuschalten.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gast
Reply to this topic...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.


×
×
  • Neu erstellen...