====== AddOn-Software einbinden in BiDiBOne ====== Die Basissoftware des BiDiBOne enthält neben den Funktionen zur Kommunikation mit dem BiDi-Bus auch das Tasksystem Cortos und einige andere Grundfunktionen sowie die Debug-Schnittstelle. Darauf sollen die verschiedenen AddOns mit möglichst einfachen Mitteln aufbauen können. ---- * Motto: Klare Trennung zwischen Basis- und AddOn-Software. ---- ===== Konflikte ===== Da es durchaus denkbar und sogar erstrebenswert ist, mehrere AddOn-Komponenten gemeinsam zu verwenden, wird eine Konvention eingeführt, die Konflikte zwischen den einzelnen Teilen verhindern soll. Verwendete Portpins und Timer werden in der entsprechenden Header-Datei wie folgt bekanntgegeben: {{:codehilfe:oc_i_need_port.jpg|}} (Hier am Beispiel Port A, Pin 0) Ebenso muss die Verwendung der schnellen Semaphoren bekannt gemacht werden: {{:codehilfe:oc_i_need_c6.jpg|}} (Hier am Beispiel Semaphore Typ C, Bit 6) **Da es sich "nur" um eine Konvention handelt, ist hier die Disziplin des Einzelnen gefordert!** Sollte in der Basis ein neues Flag verwendet werden, führen wir eine entsprechende Deklaration ein. Eine Doppelbenutzung durch ein AddOn, das der Konvention folgt, deckt der Compiler dann schnell auf. Sollte der Compiler eine Doppelbenutzung aufdecken, so kann man den 'konkurrierenden' Nutzer einfach ausfindig machen, wenn man vor //#error Port conflict A7// temporär ein //#define I_NEED_PORTA7 1234// setzt. Der Compiler zeigt dann die Stelle mit //previous define was here// an. ===== AddOn-Hooks ===== Die Basissoftware enthält definierte "Hooks", um die Software der AddOns einzubinden. Im Repository der Gruppe BiDiB im Projekt **AddOnStub** steht ein Muster mit allen notwendigen Dateien zur Anbindung eines eigenen AddOns an den BiDiBus zur Verfügung. Die entsprechenden Quellen sind im Unterverzeichnis **src/addon** zu finden. Zusätzlich liegt im Unterordner **conf** (configuration) das Muster einer Beschreibungsdatei für die Tools [[monitor|BiDiB-Monitor]] und [[wizard|BiDiB-Wizard]] vor. Der Unterordner **env** (environment) ist für Hilfsmittel zur Entwicklung vorgesehen und enthält u.A. eine Projektdatei für das AtmelStudio 6. **Tipp:** Kopiert man diese Projektdatei in den MyAddOn-Ordner, kann man durch Doppelklicken das AtmelStudio starten. Das sieht dann etwa so aus: {{:codehilfe:oc_addon_solution.jpg?200|}} (Im Bild zu sehen der **Link** auf das main-Modul der BiDiBone-Basis-FW. Die anderen Links auf Module in der Basis verstecken sich im Ordner: library.) ==== Baugruppen-Modell ==== Das Modell einer Baugruppe wird in der Headerdatei ''addon_model.h'' definiert. Für die eindeutige Erkennung am BiDi-Bus sind die folgenden Angaben für die Geräte-ID zu machen: {{ codehilfe:oc_deviceid.jpg |}} Hier am Beispiel einer **Eigenbaugruppe** (''BIDIB_VENDOR_ID=13'') und der Produkt-ID 116. Die Produkt-IDs werden an der angegebenen Adresse ([[http://www.opendcc.de/elektronik/bidib/opendcc_bidib.html]]) vergeben. Mit den allgemeinen Definitionen können bestimmte Zusatzfunktionen aus der Basis-Firmware aktiviert und das Standardverhalten eingestellt werden: {{ codehilfe:oc_model.jpg |}} In der Basis-Firmware wird geprüft, ob diese notwendigen Definitionen gemacht wurden und gfls. ein Compilerfehler angezeigt. ==== Versionsdaten ==== Die Versionsinformationen werden über den BiDiBus an den Host übertragen. Außerdem fließen sie in den Namen der Firmware-Dateien ein. Fehlen sie, wird ein Compiler-Fehler erzeugt. Die Versionsdaten für das AddOn werden in der Header-Datei: ''addon_version.h'' definiert. {{ :codehilfe:oc_version_h.jpg |}} Hier am Beispiel der originalen ''version.h''. Durch die feste Struktur lassen sich diese Versionsdaten für alle BiDiBOne-AddOns gleichermaßen z.B. mit einem Skript lesen und die Firmware-Datei eindeutig kennzeichnen. ==== Baugruppen-Fähigkeiten (Features) ==== "//... Über features teilt die Hardware dem PC-Programm ihre Fähigkeiten mit (also z.B. 'ich kann Lokadresse UND Richtung erkennen'). Das kann eine Eigenschaft der Hardware sein (wer kann, der kann), das kann aber auch explizit abgewählt werden - weil eben z.B. eine Dreileiteranlage angeschlossen ist, wo die Richtungsinformation des Belegtmelders wertlos ist. Features sind in der Norm auf bidib.org erläutert...//" (siehe [[http://www.bidib.org/protokoll/bidib_general.html|BiDiB, ein universelles Steuerprotokoll für Modellbahnen]]) Die Features werden in ''addon_features.h'' definiert und müssen den Fähigkeiten der Baugruppe angepasst werden. {{:codehilfe:oc_features_h.jpg|}} Dort werden sinnige Indices für die in ''bidib_message.h'' vorgegebenen Features definiert. Die Tabelle feature[] enthält den aktuellen Wert des Features und seine Grenzwerte (min/max). Für eine weitere Verarbeitung kann eine ''notify_function'' angegeben werden. (Im Beispiel gibt es keine.) Im Gegensatz zu CVs sind Features eineindeutige Standardobjekte und damit genehmigungspflichtig. D.h. eine CV kann man definieren, wie man lustig ist, ein Feature nicht. Das ist der Grund, weshalb nur die in bidib_messages.h abgesprochenen und standardisierten Werte erlaubt sind. Zum Lesen der Features stehen die zwei Funktionen aus der Header-Datei ''features.h'' zur Verfügung: {{:codehilfe:oc_get_feature_index.jpg| }} Mit Hilfe dieser Funktion erhält man über die in ''bidib_messages.h'' vorgegebenen Features den Index auf die interne Tabelle. Ist das Feature ungültig bzw. steht es nicht in der tabelle, wird -1 geliefert, andererseits der Index. {{:codehilfe:oc_get_feature_index_value.jpg |}} Mit dem oben erhaltenen Index wird mit dieser Funktion der Wert des Features gelesen. Diese Funktion sollte nur aufgerufen werden, wenn der oben erhaltene Index größer oder gleich 0 ist. Wenn ein Host-System eine Nachricht vom Typ: ''MSG_LC_CONFIG_SET'' abschickt, wird die Funktion ''config_sport_addon'' aufgerufen: {{:codehilfe:oc_config_sport_addon.jpg|}} Soll die Anfrage unterstützt werden, sind die entsprechenden Informationen des SPORT-Accessorys mit den übergebenen Informationen zu setzen und ''1'' zu liefern. Anderenfalls reicht die Rückgabe einer ''0''. Analog wird verfahren, wenn ein Host-System mit der Nachricht: ''MSG_LC_CONFIG_GET'' die SPORT-Eigenschaften anfordert, dann wird die Funktion ''addon_sport_query'' aufgerufen: {{:codehilfe:oc_addon_sport_query.jpg|}} Soll die Anfrage unterstützt werden, sind die angeforderten Angaben mit den entsprechenden Informationen des SPORT-Accessorys auszufüllen und ''1'' zu liefern. Anderenfalls reicht die Rückgabe einer ''0''. ==== EEPROM (CV-Daten) ==== Die so genannten CV-Daten werden im EEPROM des Bausteins abgelegt. Für die Organisation im AddOn sind vier Dateien zuständig: * **addon_cv_define.h** ⇒ definiert die Variablen * **addon_cv_declaration.h** ⇒ deklariert die Variablen für die notwendigen Strukturen * **addon_cv_data.h** ⇒ legt den Inhalt im EEPROM fest * **addon_cv_features.h** ⇒ legt die Features im EEPROM fest Beispiele aus der OneControl: **addon_cv_define.h** (Variablendefinition): {{ :codehilfe:oc_addon_cv_definitions.jpg |}} **addon_cv_declaration.h** (Variablendeklaration): {{ :codehilfe:oc_addon_cv_declaration.jpg |}} **addon_cv_data.h** (CV-Daten im EEPROM): {{ :codehilfe:oc_addon_cv_data1.jpg |}} **addon_cv_features.h** (Features im EEPROM): {{ :codehilfe:oc_addon_cv_features.jpg |}} ==== Initialisierung und Shutdown ==== Zur Initialisierung ruft das Basissystem Funktionen des AddOns an mehreren Stellen im Modul ''addon.c'' auf: * Nach Abschluss der Basisinitialisierung und **vor** Freigabe der **Interrupts** die Funktion **''init_addon()''** * Beim Herunterfahren die Funktion **''close_addon()''** * Nach Abschluss der gesamten Initialisierung sowie **nach** Freigabe der **Interrupts** und innerhalb einer Task die Funktion **''power_up_addon()''** * Während der Power-Up-Phase wird der Zustand der Initialisierung in der Funktion **''init_finished_addon''** abgefragt. Die Initialisierung wird genau dann fortgesetzt, wenn hier 0 geliefert wird! * Jedesmal nach Initialisierung der BiDiB-Komponente, also sowohl nach einem Neustart als auch nach dem Befehl, den Knoten zurückzusetzen, wird die Funktion **''restart_addon()''** aufgerufen.//(seit V.00.06)// {{codehilfe:oc_addon_c.jpg |}} Die Funktionen sind in der Quelle ''addon.c'' vorbereitet. Von dort aus können alle weiteren Initialsierungen und "Shutdowns" aufgerufen werden. Hier am Beispiel OneControl in einer frühen Version. Besondere Beachtung ist der ''power_up_addon''-Funktion zu zollen. Sie wird zu Beginn der Taskverwaltung aufgerufen und ist wie eine "normale" Task zu programmieren. Beendet wird sie erst, wenn die Anwendung ''-1'' zurückliefert. Während die Power-Up-Tasks noch laufen, startet das Tasksystem alle angemeldeten Tasks, die als ''ready'' gekennzeichnet wurden! Um Initialisierungskonflikte zu vermeiden, dürfen die vom AddOn abhängigen Taks erst zum Schluss der Power-Up-Task freigegeben werden! {{:codehilfe:oc_addon_init_finished.jpg |}} Zur Synchronsierung mit dem Basissystem wird die Funktion ''init_finished_addon'' aufgerufen. Das Verfahren ist notwendig, wenn ein AddOn erst im weiteren Programmablauf (z.B. während einer eigenen länger dauernden Task) die Initialisierung fertig stellen kann. In manchen Fällen ist ein Neustart der Anwendung notwendig, wenn sich z.B. die Struktur des Knotens durch Umkonfiguration geändert hat. Wenn das AddOn dieser BiDiB-Befehl erreicht (oder auch nach einem Neustart der Baugruppe), wird die Funktion: ''restart_addon()'' aufgerufen. {{:codehilfe:oc_restart_addon.jpg |}} Dort können alle Neu-Initialisierungen organisiert werden, die einen Neustart des Knotens notwendig machen. Hier am Beispiel der OneControl, bei der bei Umkonfigurierung der Ein- und Ausgänge des GPIO-Bausteins ein Neustart nötig wird. \\ Weitere so genannte Callback-Funktionen im Modul ''addon.c'' werden weiter unten in den Kapiteln: [[addon_einbinden#Accessory-Behandlung|Accessory-Behandlung]], [[addon_einbinden#Makroausführung|Makroausführung]] und [[addon_einbinden#Hilfseingabe]] erläutert. ---- ==== Taskverwaltung ==== Zur Einbindung in die Taskverwaltung ''cortos'' sind in der Headerdatei: **addon_tasklist.h** die folgenden Einträge erforderlich: * **Prototypdefinition ''ADDON_PROTOTYPES''** * **Task-ID ''ADDON_TASKENUMS''** * **Taskdefinition ''ADDON_TASKLIST''** * **FIFO-Definitionen ''ADDON_FIFOS''** Alle Teile werden an den betreffenden Stellen in der Taskverwaltung eingebunden. {{ codehilfe:oc_addon_tasklist_h.jpg |}} Hier am Beispiel OneControl in einer frühen Entwicklungsphase. (Die FIFO-Definitionen schließen sich entsprechend an.) ---- Anmerkung: Es ist zu überlegen, ob das Basis-System verschiedene Prioritätsgruppen unterstützen sollte. Dann würden die einzelnen Blöcke entsprechend in die Taskliste der Basis eingefügt. ---- ==== Accessory-Behandlung ==== Die BiDiB-Nachrichten werden in der Basissoftware abgehandelt. Allerdings kann für die abschließende Benachrichtigung die Bewertung des AddOns notwendig sein. Nach Abarbeitung eines Accessorys bittet die Basissoftware das AddOn mit dem Aufruf der Funktion **''accessoryStateAddOn(...)''** um ein "Schlusswort". Das kann eine Gutmeldung einfacher Art oder mit Zusatzinformationen laut BiDiB-Protokoll sein. Aber auch die Meldung eines Fehlers während der Bearbeitung des angefragten Accessorys ist möglich. Hat das AddOn nichts zu sagen, wird eine Standardantwort an das Host-System geschickt. {{:codehilfe:oc_accessorystateaddon.jpg|}} Am Beispiel der OneControl. Der Weichenmanager schickt eine vom angeforderten Accessory abhängige Information in der übergebenen Struktur zurück und quittiert mit "1". Dadurch wird seine Nachricht an den Host verschickt. ==== Makroausführung ==== Nach Erkennen eines Accessory-Set-Befehls wird die Funktion **''performAddOnMacro''** im Modul ''addon.c'' aufgerufen: {{ codehilfe:oc_performaddonmacro.jpg|}} Hier am Beispiel der OneControl, die an dieser Stelle wird nur den Typ: BIDIB_OUTTYPE_SPORT unterstützt. Die Argumente sind: * lstate => Schaltbefehl * lvalue => Wert des Makropunktes * accessory => Nummer des Accessorys für das "Schlusswort" Die Unterscheidung des Accessory-Typs kann am Beispiel abgelesen werden. Da diese Aktionen während des Betriebs innerhalb einer Task laufen, gilt auch hier, dass bei komplexeren Funktionen die folgende Bearbeitung lediglich initiiert werden sollte. Die eigentliche Funktionalität sollte in einer entsprechenden Task durchgeführt werden. ==== Hilfseingabe ==== Die Basis-Firmware unterstützt Eingänge in zwei Arten: * Meldung über den BiDi-Bus nach einer ''MSG_LC_KEY_QUERY''-Nachricht * Starten von Makros über externe Eingänge In beiden Fällen wird die Callback-Funktion **''check_input_addon(...)''** aufgerufen. Sie muss den Zustand des übergebenen Eingangs liefern. Hat das AddOn diese Fähigkeit nicht, muss FALSE geliefert werden. {{:codehilfe:oc_check_input_addon.jpg|}} Beachte: Derzeit werden für die Makroausführung nur die Zustände der ersten 8 Eingänge abgefragt. ---- **Spontane Keyboard-Ereignisse** werden mit dem integrierten **[[softwarebausteine:Event-System|Event-System]]** realisiert. ---- ==== Debug-Schnittstelle ==== Auch das ''debug_if''-Modul enthält "Hooks" zur Unterstützung der AddOns. * **Aufruftabelle ''ASCII_PARSE_TAB_ADDON''** * **Überschrift ''PA_info_addon()''** * **Zusammenfassung ''PA_help_addon()''** Diese Teile werden ebenso an den entsprechenden Stellen im Basis-Projekt eingebunden. Die Aufruftabelle muss in der vorbereiteten Headerdatei: **''addon_debug_if.h''** definiert werden. Hier am Beispiel OneControl mit DMX-Vorgabe: {{codehilfe:oc_addon_debug_if_h.jpg |}} Zusätzlich müssen hier auch die Prototypen für die eigentlichen Debug-Funktionen definiert werden. Die Texte für Überschrift und Zusammenfassung werden in der vorbereiteten Quelle **''addon_debug_if.c''** formuliert: {{codehilfe:oc_addon_debug_if_c.jpg |}} Anschließend werden die eigentlichen Debug-Funktionen programmiert. ===== Zusammenfassung ===== ==== Vorgehen ==== - In ''addon_model.h'' Modell konfigurieren - In ''addon_version.h'' Versionsinformationen definieren - In ''addon_features.h'' Fähigkeiten definieren - EEPROM-Daten festlegen (CV) - ''addon_cv_define.h'' Variablen definieren - ''addon_cv_declaration.h'' Variablen deklarieren - ''addon_cv_data.h'' Inhalte festlegen - ''addon_cv_features.h'' Fähigkeiten festlegen - In ''addon.c'' Initialisierung (inkl. Power-Up) und "Shutdown" sowie Neustart veranlassen - In ''addon.c'' Anfragen zu Features verwalten - In ''addon_tasklist.h'' Tasks definieren - In ''addon.c'' "Schlusswort" und Makrofunktionen sowie gfls. Eingangsschalter für Makros initiieren - In ''addon_debug.c/h'' Debugfunktionen einbauen ==== Hooks ==== === Definitionen === == Versionsdaten == * **MAIN_VERSION** Hauptversionsnummer * **SUB_VERSION** Unterversionsnummer * **COMPILE_RUN** Kompilierlauf * **BUILD_YEAR** Herstellungsdatum: Jahr * **BUILD_MONTH** Herstellungsdatum: Monat * **BUILD_DAY** Herstellungsdatum: Tag == Baugruppenkennzeichnung == * **BIDIB_VENDOR_ID** vendor ID = 13 * **BIDIB_PRODUCT_ID** product ID see http://www.opendcc.de/elektronik/bidib/opendcc_bidib.html * **CLASS_ACCESSORY** occurence of accessory messages (0/1=no/yes) * **CLASS_OCCUPANCY** occurence of occupancy messages (0/1=no/yes) * **CLASS_SWITCH** occurence of switch messages (0/1=no/yes) == Allgemeine Definitionen == siehe **''addon_model.h''** * Aktiviert Zusatzfunktionen aus der Basis-Software, z.B. Servos (**''SERVO_ENABLED''**), LED-Blinken (**''BLINK_MORSE_ENABLED''**). * Notwendige Angaben, z.B. über die Anzahl von Ein- und Ausgängen, z.B. **''NUM_OF_INPUTS''**, **''NUM_OF_SPORTS''** == Fähigkeiten == siehe **''addon_features.h''** * Fähigkeiten des AddOns laut [[http://www.bidib.org/protokoll/bidib_general.html|BiDiB, ein universelles Steuerprotokoll für Modellbahnen]], z.B. **''FEATURE_STRING_SIZE''** oder **''FEATURE_CTRL_INPUT_COUNT''**. == Taskverwaltung cortos == * **ADDON_PROTOTYPES** Prototypdefinitionen * **ADDON_TASKENUMS** Task-IDs * **ADDON_TASKLIST** Taskdefinitionen * **ADDON_FIFOS** FIFO-Definitionen == CV-Werte == * EEPROM Version, Herstellerkennzeichnung, ... CV1-CV7 * (Reserviert CV8-CV69) * Allgemeine Einstellungen CV70 * (Reserviert CV71-80) * Servos (wenn konfiguriert) ab CV81 * Accessorys (wenn konfiguriert) ab CV209 * **AddOn spezifische Werte ab CV389** === Funktionen === == Start und Stopp == * **init_addon()** Funktionsaufruf zur Initialisierung **vor** Freigabe de Interrupts * **power_up_addon()** ask zur weiteren Initialsierung **nach** Freigabe der Interrupts * **init_finished_addon()** Abfrage, ob AddOn mit INitialisierung fertig ist * **restart_addon()** Funktion zum Neustart nach Knoten-Reset * **close_addon()** Funktion zum Schließen des AddOns insbesondere der Interrupts == Betrieb == * **performAddOnMacro()** Ausführen der Makros eines AddoOns * **accessoryStateAddOn()** "Schlusswort" bei Beendigung des Accessorys * **check_input_addon()** Zustandsabfrage der ersten 8 Eingänge zum Makrostart == Debug-Schnittstelle == * **ASCII_PARSE_TAB_ADDON** Aufruftabelle der einzelenen Debug-Befehle * **PA_info_addon()** Überschrift * **PA_help_addon()** Zusammenfassung