Top Banner
Neuron-C Fakultät Informatik Institut für Angewandte Informatik Professur Technische Informationssysteme
39

Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

Sep 07, 2019

Download

Documents

dariahiddleston
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

Neuron-C

Fakultät Informatik Institut für Angewandte Informatik

Professur Technische Informationssysteme

Page 2: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

2

Inhaltsverzeichnis 1. Allgemeines zur Verwendung von Neuron-C 1.1 Programmaufbau in Neuron-C 1.2 Datentypen in Neuron-C 1.3 Speicherklassen 1.4 Spezifikation von Speicherbereichen 1.5 Weitere Unterschiede von Neuron-C zu ANSI-C 2. Das ereignisgesteuerte Betriebssystem 2.1 Der Scheduler 2.2 Ereignisse 3. Die Neuron-Chip-Hardware 3.1 IO-Geräte 3.2 Timer 4. Programmierung des Neuron-Chips als Single-System 4.1 Erste Schritte 4.2 Programmierung der Timer 4.3 IO-Pins und IO-Kanäle 5. Kommunikation über Netzwerkvariablen 5.1. Allgemeines 5.2. Ereignisse für Netzwerkvariable 5.3. Synchrone Netzwerkvariablen 5.4. Netzwerkvariablen mit Abfrage (Polling) 5.5. Überwachung von Netzwerkvariablen 5.6. Authentication - Autorisierung einer Übertragung 6. Kommunikation mittels expliziter Botschaften 6.1. Schichten der NEURON Chip Software 6.2. Allgemeines zu Botschaften 6.3. Fertig-Ereignisse für Botschaften 6.4. Botschaften und der Preemption Modus 6.5. Asynchrone und direkte Ereignisverarbeitung 6.6. Anfrage - Antwort - Mechanismus (Request - Response) 6.7. Puffer 7. Bemerkungen zum Speicher-Management 7.1. Adreß-Tabellen 7.2. Allokieren von Puffern 7.3. Anzahl der Empfangs-Transaktionen 8. Verschiedenes 8.1. Scheduler-Reset-Mechanismus 8.2. Der Watchdog-Timer 8.3. Zusätzliche vordefinierte Ereignisse vom Netzwerk Management Tool 8.4. Fehler-Behandlung 9. Komplexes Beispiel

Page 3: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

3

1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem, welches stark an die Programmiersprache C angelehnt ist und wesentliche Elemente dieser enthält. Erweitert wurde das System durch sprachliche Möglichkeiten zur Bedienung von internen und externen Ereignissen, sowie zur Kommunikation zwischen den Neuron-Chips mittels LONWORKS-Protokoll. Es sollte deshalb leicht fallen, Neuron-C zu erlernen, wenn man über Erfahrungen in der C-Programmierung verfügt. Aus diesem Grunde wird im Folgenden nur auf die Besonderheiten von Neuron-C eingegangen. 1.1 Programmaufbau in Neuron-C Anders als in C gibt es in Neuron-C keine main()-Prozedur, da das System vollständig ereignisorientiert ist. Auf Ereignisse kann mit Hilfe der when()-Funktion reagiert werden. 1.2 Datentypen in Neuron-C In Neuron-C werden standartmäßig 8-Bit- und 16-Bit-Datentypen unterstützt. Folgende Tabelle gibt Aufschluß über die verschiedenen Typen: Typ Datenbreite [ signed | unsigned ] long int 16 Bit [ signed | unsigned ] char 8 Bit [ signed | unsigned ] [ short ] int 8 Bit enum ( int-Datentyp) 8 Bit Eine Gleitkomma-Bibliothek ist verfügbar und bei Bedarf nachladbar. Für deren Benutzung sei auf ent-sprechende Literatur verwiesen. 1.3 Speicherklassen In Neuron-C sind ähnlich wie in ANSI-C folgende Speicherklassen verwendbar: auto const extern static Zusätzlich folgende Klassen: config plaziert Konfiguration im chip-eigenen EEPROM network Netzwerkvariable system erlaubt Zugriff auf Firmware-Funktion 1.4 Spezifikation von Speicherbereichen Im Unterschied zu ANSI-C kann in Neuron-C genau spezifiert werden, wo im Neuron-Chip Daten und Code abgelegt werden sollen. Dazu existieren folgende Präfixe: eeprom belegt chip-eigenen EEPROM-Speicher far, ram belegt chip-eigenen RAM-Speicher 1.5 Weitere Unterschiede von Neuron-C zu ANSI-C - es wird standartmäßig keine Gleitkomma-Arithmetik unterstützt - short int wird als 8-Bit-Datentyp statt als 16-Bit-Datentyp realisiert long int wird als 16-Bit-Datentyp statt als 32-Bit-Datentyp realisiert - register und volatile Klassen werden nicht unterstützt - struct und unions können nicht als Rückkehrwerte, Prozedurparameter oder automatic-Variablen verwendet werden - es sind keine Felder als automatic-Variablen möglich - in Verwendung mit Netzwerkfunktionen können keine Pointer verwendet werden - für Bezeichner sind die ersten 16 Zeichen relevant - standartmäßig sind nur die Bibliotheken bzw. Header-Dateien STDDEF.H, STDLIB.H, LIMITS.H installiert

Page 4: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

4

2. Das ereignisgesteuerte Betriebssystem Auf dem Neuron-Chip läuft eine fest installierte Firmware, die ein komfortables ereignisorientes Betriebs-system darstellt. Ereignisorientiert heißt dabei, daß das Betriebssystem Timer, Ein-/Ausgabe-Ereignisse und Netzwerkereignisse verwaltet und als Hochspracheninterface dem Programmierer zur Verfügung stellt. Eine der wichtigsten Programmfunktionen stellt dabei der Task-Scheduler dar, welcher in einer festen Reihenfolge alle möglichen Ereignisse auf deren Auftreten hin untersucht und gegebenfalls in entsprechende Funktionen verzweigt. 2.1 Der Scheduler Der Scheduler stellt das Herz der Neuron-Firmware dar. Er verwaltet alle eintreffenden Meldungen und Ereignisse auf folgende Weise:

TASK

TASK

RESETTASK

TASK

PRIORITYWHEN

PRIORITYWHEN

TASK

WHEN

WHEN

WHEN

PRIORITYWHEN

TASK

F F

T T T

F

F

T

T

F

. . .

. . .

TASKSCHEDULER

Der Scheduler prüft in der Reihenfolge des Auftretens von when-Bedingungen im Programm, ob eine solche erfüllt ist, und wenn dies der Fall ist, so verzweigt er in die zugehörige TASK-Routine. Eine when-Bedingung und deren TASK-Routine ist also die Antwort auf ein Ereignis. Nach Abfrage und eventueller Abarbeitung einer when-Bedingung wird getestet, ob eine priority when-Bedingung erfüllt ist und diese dann entsprechend verarbeitet. Die priority when-Bedingung stellt somit eine höher privilegierte when-Bedingung dar, welche dazu genutzt werden kann, um besonders zeitkritische Routinen zu verwirklichen. 2.2 Ereignisse Das Betriebssystem der Neuron-Chips stellt Ereignisse in Form von logischen Variablen zur Verfügung. Somit kann auf alle Ereignisse durch einen entsprechenden Vergleich reagiert werden. Es sollte bevorzugt in den when-Bedingungen auf Ereignisse reagiert werden, um das betriebssystemeigene Scheduling nicht zu unterbrechen. Da when-Bedingungen nicht schachtelbar sind, ist es jedoch denkbar, Ereignisvariable auch in for, if und while-Ausdrücken zu verwenden.

Page 5: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

5

Folgende Ereignisse werden vom System standartmäßig unterstützt: -Timer-Ereignisse werden generiert, wenn die auf dem Chip vorhandenen Counter und Timer einen Nulldurch- lauf haben -IO-Ereignisse treten auf, wenn an den externen IO-Ports Änderungen stattfinden -Netzwerk-Ereignisse werden erzeugt, falls im angeschlossenen Netzwerk Übetragungen stattfinden -System-Ereignisse entstehen bei Ausführung spezieller Systemroutinen wie beispielsweise der RESET-Routine Eins der wichtigsten Ereignisse ist das RESET-Ereignis, welches auftritt, wenn der Neuron-Chip intitialisiert bzw. durch ein externes RESET-Signal rückgesetzt wird. Es tritt somit zu Beginn jedes neuen Programmstarts auf und sollte verwendet werden, um alle wichtigen Systemvariablen zu reinitialisieren . Andere benutzereigne Ereignisse können definiert und benutzt werden. Weiterhin kann bei vielen Ereignissen auch auf entsprechende Rückkehrwerte zugegriffen werden, welche zum Ereignis zugehörige Werte enthalten.

Page 6: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

6

3. Die Neuron-Chip-Hardware 3.1 IO-Geräte Die IO-Geräte auf dem Neuron-Chip stellen die Vebindung zur Außenwelt her. Folgendes Schema gibt einen Überblick über die Organisation dieser Geräte auf einem LON-Works-Knoten:

4 zu 1MUX

Counter/Timer 1

Counter/Timer 2

IO_7

IO_6

IO_5

IO_4

IO_1

IO_0

IO_2

IO_3

IO_8

IO_9

IO_10

frei

frei

frei

frei

frei

Hierbei ist zu beachten, daß die IO-Leitungen 0..1 sowie 4..7 schon hardwaremäßig vorbelegt sind. Auf den LON-Works-Knoten sind dabei die Leitung 0 als Ausgabe an eine sichtbare LED gekoppelt, während Leitung 4 eine Eingabe mittels Taster realisiert. Alle anderen Ein- und Ausgabeleitungen sind frei verwend- und konfigurierbar. 3.2 Timer Auf den Neuron-Chips existieren zwei Typen von Timern: Millisekunden- und Sekunden-Timer. Beide Zähler sind 16 Bit breit und können dementsprechend von 1 .. 65535 ms bzw. 1 .. 65535 s zählen.

Page 7: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

7

4. Programmierung des Neuron-Chips als Single-System 4.1 Erste Schritte Die Programmierung des Neuron-Chip ist komfortabel über die dem ANSI-C ähnliche Programmiersprache ´Neuron-C´ möglich. Zu beachten ist jedoch, daß die Neuron-Chip-Software ereignisgesteuert ist und sich somit die Struktur der Neuron-C Programme erheblich von ANSI-C Programmen unterscheidet. Auf weitere Unterschiede wurde schon weiter vorn hingewiesen. Das erste Programm: #include "first.h" int index; when (reset) { index = 0; } In diesem Programm wird in der when-Bedingung, welche auf das RESET-Ereignis reagiert, die Variable index initialisiert. Weiterhin wird die Header-Datei "first.h" und damit evtl. entsprechende Objekt-Dateien zum endgültigen Programm hinzugelinkt. Aus diesem Beispiel ist die allgemeine Struktur der Neuron-C Programme erkennbar: [ #include ".." ] <- Header einbinden [ Variablendeklaration ] <- Variablen deklarieren [ when ( Ereignis1 ) Task1 ] <- Reaktion auf Ereignisse [ when ( Ereignis2 ) Task2 ] ... Syntax der when-Bedingung: [priority] when ( Ereignis) task; Bei Eintritt von Ereignis wird die Routine task ausgeführt. Durch das Schlüsselwort priority kann die Ausführung höher privilegiert werden als die normale Ausführung. 4.2 Programmierung der Timer Bis jetzt kann das Programm noch nicht auf irgendwelche andere Ereignisse als dem RESET-Ereignis reagieren. Um einen zeitabhängigen Programmablauf zu realisieren, existieren die Timer bzw Zähler. Das Betriebssystem stellt insgesamt 15 Timer zur Verfügung, welche als Sekunden- und Millisekunden-Timer konfiguriert werden können. Die Zeitdauer kann bei beiden Timertypen mit einem 16-Bit Wert dargestellt werden, so daß sich Zeiten von 0..65535s bzw. 0..65535ms einstellen lassen. Weiterhin ist es möglich, Timer als einmaligen Ablauf oder sich wiederholende Folge zu realisieren. Ist ein Timer abgelaufen, so wird ein entsprechendes Ereigniss generiert, auf welches in einer when-Bedingung reagiert werden kann. Syntax der Timerdeklaration: mtimer [ repeating ] timer_name; // ms-Timer stimer [ repeating ] timer_name; // s-Timer Mit diesen Anweisungen können Timer deklariert werden, wobei durch Zusatz von repeating ein sich selbst wiederholender Timer definiert werden kann.

Page 8: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

8

Start eines Timers: timer_name = start_wert; // Zeitdauer = startwert in [s/ms] Stop eines Timers: timer_name = 0; Ablesen eines Timers: neu_wert = timer_name; Reaktion auf ein Timerereignis: timer_expires // wird TRUE, wenn irgendein Timerereignis auftrat timer_expires( timer_name ) // wird TRUE, wenn der Timer timer_name abgelaufen ist Beispiel für Timerverwendung: int index; mstimer repeating timer_one; stimer timer_two when (reset) { timer_one = 200; // wiederholender Timer mit Periodendauer 200ms timer_two = 2; // einmaliger Timer mit Zeitdauer von 2s index = 0; } when ( timer_expires ) // auf jedes Timerereignis wird reagiert { if ( timer_expires( timer_one)) index++;// explizite Testung auf Timer timer_one else index = 0; } 4.3 IO-Pins und IO-Kanäle Mit Hilfe der nach außen geführten Pins bzw. IO-Leitungen kann ein direkter Kontakt mit der Umwelt hergestellt werden. Insgesamt unterstützt das Betriebssystem 16 IO-Kanäle. Um eine der IO-Leitungen anzusprechen, ist eine entsprechende Variable zu deklarieren. Dabei sind INPUT und OUTPUT-Variablen zu unterscheiden. Es ist aber möglich, einen OUTPUT-Kanal zusätzlich als INPUT-Kanal zu deklarieren und hat damit die Möglichkeit, den zuletzt ausgegebenen Wert zurückzulesen. Syntax einer IO-Kanals-Deklaration: io_kanal input|output [ model] device_name [= initial_level]; Es existieren folgende Modelle, die ein komfortables Interface unterstützen: Für direkte IO-Kanäle sind verwendbar: -bit .. weist dem Kanal ein 1-Bit Ein- oder Ausgabe-Modell zu -nibble .. faßt die IO-Leitungen 4-7 zu einem 4-Bit breitem Modell zusammen und ermöglicht ein paralleles Interface zur Komunikation

Page 9: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

9

-byte .. benutzt 8 IO-Leitungen für das paralleles Übertragen eines Bytes -bitshift .. ermöglicht serielle Ein- / Ausgabe über eine 2-Draht-Leitung Unter Verwendung der Timer-IO sind verwendbar: -oneshot .. stellt ein Modell dar, bei dem eine IO-Leitung nach einer Ausgabe auf diesem Kanal nach einstellbarer Triggerzeitauf zu ihrem Ausgangspegel zurückkehrt. Es wird also eine Monoflop-Triggerung realisiert.

-pulsewidth .. ist ein Modell, bei dem folgende Impulsfolgen ausgegeben werden können:

-quadrature .. bestimmt Drehrichtung und Schritte eines Drehdecoders -frequency .. zur Generation eines Rechtecksignals mit bestimmbarer Frequenz -period .. mißt die Periodenzeit eines Eingangssignal -ontime .. mißt die High/Low-Periodenzeit eines Eingangssignal -pulsecount .. zählt Eingangsimpulse -triac .. ein Modell speziell für Phasenanschnittsteuerungen Eingabe über einen IO-Kanal: return_value = io_in( device_name [, args]); // liest den aktuellen Pegel vom Kanal device_name ein Außerdem ist es möglich, über die vordefinierte Variable input_value den aktuellen Rückgabewert der letzten io_in(), io_changes() oder io_update_occurs()-Anweisung zu ermitteln oder über die vordefinierte bool´sche Variable input_is_new eine Änderung des Eingangspegel zu erkennen. Ausgabe auf einen IO-Kanal: io_out( device_name, output_value [, args]); // Ausgabe von output_value auf den Kanal device_name Reaktion auf ein IO-Ereignis: io_changes [ by const_exp|to const_exp] // wird TRUE, wenn irgendeine Änderung auf den Kanälen auftrat, wobei noch spezifiziert werden kann, welche Änderung Berücksichtigung findet io_changes( device_name) [ by const_exp|to const_exp] // wird TRUE, wenn eine Änderung auf dem Kanal device_name auftrat, sonst wie oben

Page 10: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

10

Achtung! Falls in einer when-Bedingung mittels io_changes() auf ein IO-Ereignis gewartet wird, so ist es oft günstig, den Rückgabewert nicht mittels io_in() zu ermitteln, sondern auf die vordefinierte Variable input_value zurückzugreifen, welche den aktuellen Wert enthält. Dieses Vorgehen vermeidet einen zweifachen IO-Kanal-Zugriff und spart damit Rechenzeit.

Page 11: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

11

5. Kommunikation über Netzwerkvariablen 5.1. Allgemeines Eine Netzwerkvariable ist ein Objekt, das mit verschiedenen Knoten verbunden werden kann. Sie wird zuerst auf einfachen Knoten unabhängig von anderen Knoten definiert.

* Einfache Deklarationen sehen folgendermaßen aus: network output SNVT_lev_disc Var_Name1 network input SNVT_lev_disc Var_Name2 * Vollständiger Syntax: network inputoutput [netvar-modifier] [class] type [connection-info] identifier [= initial-Wert]; network inputoutput [netvar-modifier] [class] type [connection-info] identifier [array-grenze] [= initial-Wert]; dabei bedeutet: - input .. Variable lesen - output .. Variable schreiben Die auf den einzelnen Knoten definierten Netzwerkvariablen werden vom Network Management Tool unter dem Bezeichner "Temperatur" (siehe Grafik) verbunden. Auf einem Knoten können bis zu 62 Netzwerkvariablen definiert werden.. Mit dem LONBUILDER Microprocessor Interface Program ist es möglich, bis zu 4096 Netzwerkvariablen zu definieren. Netzwerkvariablen können auch in Form von eindimensionalen Arrays vereinbart werden. Ein Knoten, der die Netzwerkvariable schreibt, kann mit mehreren Knoten, die die Netzwerkvariable lesen, verbunden werden. Der Empfang einer aktualisierten Netzwerkvariable erfolgt nicht gleichzeitig. Ein Lese-Knoten kann eine Netzwerkvariable intern ändern, ohne daß die anderen Knoten davon erfahren. Man kann auch für eine Netzwerkvariable zwei Schreib-Knoten vereinbaren. Dabei ist zu beachten, daß eine Änderung der Netzwerkvariable, die Schreib-Knoten Nr. 1 vornimmt, vom Schreib-Knoten Nr. 2 nicht erkannt werden kann. Netzwerkvariablen werden nicht sofort gesendet bzw. empfangen, sondern erst nach Ablauf einer critical section. Modifikationen von Netzwerkvariablen - [netvar-modifier] sync / synchronized: bei mehrmaligem Update einer Netzwerkvariablen innerhalb eines Tasks wird nur der

letzte Wert geschickt. polled: kann nur für Netzwerkvariablen verwendet werden, die als output deklariert sind. Eine Netzwerkvariable

wird nur über das Netz geschickt, wenn vom Empfänger eine entsprechende Aufforderung eingeht. Es erfolgt demzufolge kein automatisches Verschicken eines neuen Wertes.

Page 12: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

12

Klassen von Netzwerkvariablen - [class] Diese Klassen sind spezielle Speicherklassen. const : Netzwerkvariablen, die nicht vom Programm während der Laufzeit geändert werden können. eeprom: Netzwerkvariablen, die so deklariert sind, werden im EEPROM gespeichert, so daß sie bei einer

Stromabschaltung nicht verlorengehen. config: spezifiziert eine konstante Netzwerkvariable, die nur vom Network Management Tool bzw. Network

Controller geändert werden kann. Netzwerkvariablen, die ohne Spezifikationen deklariert werden, sind global. Sie werden im RAM des Neuron Chips gespeichert. Informationen über Verbindungen von Netzwerkvariablen - [connection-info] connection-info: Optionales Feld, das zusätzliche Attribut für Netzwerkvariablen-Verbindungen enthält. Kann

nur vom Management Tool geändert werden, wenn sie als nonconfig deklariert wurde. -> Für zusätzliche Informationen zur Deklaration siehe Neuron C Programmer's Guide Seite 3-10 und C-76ff. Inititalisierung von Netzwerkvariablen Beim Programmstart sollten alle Variablen auf einen vernünftigen Wert initialisiert werden. Dies ist besonders für input - Netzwerkvariablen wichtig. Auch für eeprom und config deklarierte Variablen ist dies notwendig. Initialisierungen werden nur beim Einschalten oder bei einem Reset (wenn nicht als const, eeprom oder config deklariert) vorgenommen. network input SNVT_temp nv_temp = 2692; Typen von Netzwerkvariable Diese Typen sind bei der Compilierung eines Programms wichtig, da in diesem Fall der Compiler evtl. Fehler erkennen kann. Für das Verbinden der Knoten nach der Erstellung des Programms sind gleiche Typen für verbundene Netzwerkvariable erforderlich. ACHTUNG: Netzwerkvariablen dürfen nicht als Pointer deklariert werden. Auch die Verwendung des '&' ist unzulässig. Eine Netzwerkvariable kann eine maximale Größe von 31 Bytes haben. Für ein Array gilt: Jedes Array-Element kann maximal 31 Bytes groß sein. Wird ein Array-Element über das Netz aktualisiert, so erfolgt dies erst im nächsten Task und zwar nur für das geänderte Element. [signed] long int unsigned long int signed char [unsigned] char [signed] [short] int unsigned [short] int enums (int type) structs und unions der oben genannten Typen, die Arrays, aber keine Zeiger enthalten dürfen. eindimensionale Arrays von oben genannten Typen mit bis zu 62 Elementen. Standard-Netzwerk-Variablen-Typen SNVTs Diese SNVTs sind im LONTALK-Protokoll vordefiniert. Sie sollten, wann immer es möglich ist, benutzt werden. Sie verbessern das Zusammenwirken, vereinfachen die Installation. Über den Compiler ist eine Selbst-

Page 13: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

13

Identifikation (SI) und auch die Selbst-Dokumentation (SD) möglich. Identifiziert werden bestimmte Daten, z.B. der SNVT-Index. SNVTs sind in snvt_lev.h enthalten. #include <snvt_lev.h> Beispiele: (1) Einfache Deklarationen: network input SNVT_temp temp_set_point network output SNVT_lev_disc primary_heater network output int current_lamp (2) Prioritäts-Deklarationen network output boolean bind_info(priority) fire_alarm network output boolean bind_info(priority(nonconfig)) fire_alarm (3) Wenn keine Bestätigung benötigt wird: network input SNVT_lev_contin bind_info(unackd) control_dial; Programm-Beispiel: //lamp.nc - Generic Program for a lamp. Eine input-Netzwerkvariable kontrolliert den Status der Lampe #include<snvt_lev.h> IO_0 output bit io_lamp_control; //Deklaration der Netzwerkvariable network input SNVT_lev_disc nv_lamp_state; //Konfiguration - nur vom Netzwerk Management Tool änderbar network input config SNVT_lev_disc nv_lamp_default = ST_OFF; //Ereignisgesteuerter Code when(reset) { //Setzen der Variable, wie in der Konfiguration festgelegt io_out(io_lamp_control, (nv_lamp_default == ST_OFF) ? 0:1); } when (nv_update_occurs(nv_lamp_state)) { io_out(io_lamp_control, (nv_lamp_state == ST_OFF) ? 0:1); } Die Funktion is_bound() Sie findet heraus, ob eine Netzwerkvariable mit einer anderen Netzwerkvariablen verbunden ist. Eine nichtverbundene Netzwerkvariable kann ein nv_update_succeeds Ereignis auslösen, obwohl kein aktuelles Update vorkam. Mit der is_bound() Funktion wird dies vermieden, der entsprechende Code wird nur ausgeführt, wenn eine Verbindung tatsächlich besteht. network output SNVT_lev_disc heater_2; void turn_on_heater_2(void) { if (is_bound(heater_2)) heater_2 = ST_ON; }

Page 14: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

14

5.2. Ereignisse für Netzwerkvariable nv_update_occurs [(Netzwerk-Variable)] nv_update_succeeds [(Netzwerk-Variable)] nv_update_completes [(Netzwerk-Variable)] nv_update_fails [(Netzwerk-Variable)] nv_update_occurs kann nur für input-Variablen verwendet werden, die anderen drei Ereignisse sind nur für output-Variablen vorgesehen. Die Ereignisse können mit Variablennamen qualifiziert werden. Bei Arrays tritt das Ereignis für jedes Element einmal ein. => Wird kein qualifizierter Variablenname angegeben, so wird das Ereignis für jede Netzwerkvariable wahr. nv_update_occurs Dieses Ereignis ist TRUE, wenn ein neuer Wert für eine Netzwerkvariable eingeht. when (nv_update_occurs(nv_lamp_state)) { io_out(io_lamp_control,(nv_lamp_state != ST_OFF) ? 1:0); } nv_update_fails Update oder poll einer Variable war fehlerhaft, wenn dieses Ereignis TRUE ist. Für mehrfache Netzwerkvariablen wird das Ereignis für jede Netzwerkvariable TRUE, die fehlerhaft beim Übertragen war. when (nv_update_fails(nv_switch_state)) { // Korrekturen, andere Aktionen } nv_update_succeeds Diese Ereignis ist TRUE, wenn das Übertragen der Netzwerkvariablen erfolgreich war. nv_update_completes Dieses Ereignis ist TRUE, wenn ein Update einer output-Variablen entweder erfolgreich oder mißlungen war. ACHTUNG: Wenn eine Netzwerkvariable mit nv_update_completes oder nv_update_succeeds geprüft wird, so müssen auch alle anderen Netzwerkvariablen auf diese Ereignisse geprüft werden. Dies ist einfach über eine unqualifizierte when(...) Abfrage möglich: when (nv_update_completes) { /*Anweisungen*/ } when (nv_update_succeeds) { /*Anweisungen*/ } ACHTUNG: Wenn nach einem unqualifizierten Check (nonpriority) qualifizierte when-Fälle für ein bestimmtes Ereignis folgen, dann muß das Programm mit #pragma scheduler_reset am Anfang spezifiziert werden. Dadurch können die when-Fälle vom Scheduler in geeigneter Reihenfolge bewertet werden. Wenn nur auf nv_update_fails geprüft wird, ist ein Prüfen der anderen output-Netzwerkvariable nicht notwendig. weiterführendes Beispiel Neuron C Programmer's Guide S. 3-28f

Page 15: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

15

5.3. Synchrone Netzwerkvariablen Bei nicht-synchronen Netzwerkvariablen geschieht folgendes: Updates können sich bei einer input-Variablen schneller ereignen, als sie vom Scheduler verschickt werden können. In diesem Fall wird nur der letzte Wert geschickt. Dies kann mit synchronen Netzwerkvariablen vermieden werden. Deklaration: network input sync SNVT_temp Name Wenn auf einem Knoten eine Netzwerkvariable als synchron deklariert wurde, muß die damit verbundene Variable auf dem anderen Knoten nicht zwingend als synchron deklariert sein. Der LONBUILDER erzeugt in diesem Fall aber eine Warnung. Beispiel für Variable, die verschiedene Alarmzustände enthält: network output synchronized enum { none, high_temperature, high_pressure, low_flow, control_failure, } sensor alarm; Vorteile und Nachteile synchroner Netzwerkvariablen Synchrone Netzwerkvariablen sollten nur benutzt werden, wenn dies unumgänglich ist. Die meisten Applikationen kommen mit nicht-synchronen Netzwerkvariablen aus. Ständige Updates von synchronen Netzwerkvariablen können die Ausführungsgeschwindigkeit verlangsamen, wenn dem Programm die Puffer ausgehen. Übermäßiges Nutzen von synchronen Netzwerkvariablen wirkt sich nachteilig auf die Performance aus. Synchrone Netzwerkvariablen werden benutzt, wenn der Mittelwert der Aktualisierungen festgehalten werden muß. Wird nur der absolute Wert eine Netzwerkvariablen gebraucht, werden keine synchronen Netzwerkvariablen benutzt. Bei nicht-synchronen Netzwerkvariablen geht eine Aktualisierung nur auf das Netz, wenn ein Puffer im Empfänger bereitsteht. Erfolgen auch Aktualisierungen, bevor ein Puffer frei ist, so gehen diese verloren. Bei synchronen Netzwerkvariablen wird das Programm angehalten, bis ein Puffer im Empfänger frei ist. Der Scheduler geht in diesem Fall in den "Preemption Mode". Ein nv_update_occurs-Ereignis wird bei jedem Empfang einer Netzwerkvariablen TRUE, wenn ein neuer Wert auf der Netzwerkvariablen anliegt und ein Input-Puffer frei ist. Im Gegensatz dazu wird bei nicht-synchronen Netzwerkvariablen ein nv_update_occurs-Ereignis nur einmal TRUE, obwohl mehrere Updates dieser Variablen vorliegen können. Aktualisierung von synchronen Netzwerkvariablen Synchrone Netzwerkvariablen werden immer am Ende einer critical section aktualisiert. Ist kein Puffer frei, geht das System in den Preemption Mode. (Nicht-synchrone Netzwerkvariablen werden am Ende einer critical section nur aktualisiert, wenn der Scheduler Zeit hat und ein Puffer frei ist, d.h. am Ende einer critical section wird nicht immer aktualisiert.) 5.4. Netzwerkvariablen mit Abfrage (Polling) Normalfall: Die Aktualisierung wird vom Schreib-Knoten initiiert. Mit Abfrage bedeutet: Der Lese-Knoten fordert vom Schreib-Knoten, daß der aktuelle Wert eine Netzwerkvariablen geschickt werden soll. Der Lese-Knoten kann jede input-Variable zu jeder Zeit anfordern (einschließlich Einschalten und Umschalten von offline zu online). Es kann aber passieren, daß beim Einschalten viele Knoten Abfragen verschicken (demzufolge zur gleichen Zeit), so daß ein Netzwerk-Stau die Folge ist. Im Programm stellt der Leseknoten die Anfrage mittels der poll-Funktion:

Page 16: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

16

poll ([network-var]); Ist network-var ein Array, so wird für alle Array-Elemente die Abfrage ausgelöst. Wird keine spezielle Variable angegeben, so wird die Anfrage für alle Netzwerkvariablen ausgelöst. Es ist zu beachten, daß der Wert der Netzwerkvariablen nicht sofort nach Aufruf von poll(Netzwerkvariablenname) verfügbar ist. Der Eingang des neuen Wertes wird mittels nv_update_occurs in einer when-Schleife abgefragt. Achtung: Man kann im Programm des Schreibknotens nicht explizit auf eine poll-Abfrage vom Leseknoten reagieren. * Deklaration einer Netzwerkvariablen als polled im Schreib-Knoten: network output polled type Netzwerkvariablenname; Diese Deklaration bewirkt, daß der Schreib-Knoten den neuen Wert der Variablen nicht automatisch bei einer Änderung verschickt. Es wird nur auf eine spezielle Anfrage eines Lese-Knotens der neue Wert übergeben. * Deklaration im Leseknoten: network input type Netzwerkvariablenname; Beachte: Der Typ polled wird nur im Schreibknoten angegeben. Die Abfrage vom Leseknoten und die darauffolgenden Aktionen sehen z.B. folgendermaßen aus: when (...) { poll(Netzwerkvariablenname); } when (nv_update_occurs(Netzwerkvariablenname)) {...}; 5.5. Überwachung von Netzwerkvariablen Netzwerk-Überwachung erfolgt mittels eines LONWORKS-Knotens, der viele andere Knoten überwachen muß. Z.B. muß ein Knoten, der einen Alarm anzeigt, viele Alarmsensoren überwachen. Die Sensorknoten haben eine output-Netzwerkvariable, die mit SNVT_lev_disc deklariert wurde, der Überwachungs-Knoten hat eine input-Netzwerkvariable, die ebenfalls als SNVT_lev_disc deklariert wurde. Über diesen einen Eingang laufen alle Sensorereignisse ein. Bei Änderung des Eingangs am Überwachungsknoten ist es demzufolge notwendig, den entsprechenden Sensorknoten zu finden, der für die Änderung der Variablen verantwortlich ist. Dazu kann man sich folgender Techniken bedienen: (1) Die input-Netzwerkvariable am Überwachungsknoten wird als Array definiert, jedes Array-Element wird mit einem Sensor verbunden. Bei Aktualisierung eines Array-Elements tritt ein nv_update_occurs Ereignis auf. Der Sender kann mittels nv_array_index herausgefunden werden. network input SNVT_lev_disc nv_alarm_array[50]; SNVT_lev_disc alarm_value; unsigned int alarm_node; when (nv_update_occurs(nv_alarm_array)) { alarm_node = nv_array_index; alarm_value = nv_alarm_array[alarm_node]; //........ } Die Größe des Array ist begrenzt. Mit dieser Methode können maximal 62 Sensoren auf NEURON-Chip-basierten Knoten und 4096 Sensoren auf MIP-basierten Knoten überwacht werden. (2) Der Eingang am Überwachungsknoten wird als einfacher input deklariert, die Ausgänge der Sensoren werden als polled deklariert. Es wird eine einfache Verbindung der input-Variablen mit allen Sensor-output-Variablen hergestellt. Während des Betriebes ruft der Überwachungsknoten nun der Reihe nach jeden Sensor unter Benutzung expliziter Adressen und expliziter Meldungen auf. Diese Methode ist nur verwendbar, solange die Verzögerung durch die Polling-Schleife akzeptabel ist.

Page 17: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

17

(3) Die Netzwerkvariablear im Überwachung wird als einfacher Eingang deklariert, es wird eine einfache Verbindung zu allen Sensoren hergestellt. Ändert ein Sensor-Knoten den Wert der Netzwerkvariablen, die wird ein nv_update_occurs Ereignis im Überwachungsknoten ausgelöst. Den Absender des Updates kann man nun folgendermaßen ermitteln: Mit nv_in_addr kann der Sensor gefunden werden. Dabei werden LONTALK-network-management-Botschaften benutzt, um den Knoten zu identifizieren. network input SNVT_lev_disc nv_alarm_in; SNVT_lev_disc alarm_value; nv_in_addr_t alarm_node_addr; when(nv_update_occurs(nv_alarm_in)) { alarm_node_addr = nv_in_addr; alarm_value = nv_alarm_in; // alarm_node_addr und alarm_value verarbeiten // Network Management Botschaften nutzen, um Informationen vom Knoten // alarm_node_addr zu bekommen } Read memory message wird benutzt, um den location string des Sensor-Knotens zu lesen. Diese Methode ist für eine beliebige Anzahl von Sensoren geeignet. 5.6. Authentication - Autorisierung einer Übertragung Dies ist eine spezieller Service zwischen einem Schreib-Knoten und 1 bis 63 Lese-Knoten. Hiermit kann die Identität eines Schreibknotens geprüft werden. Z.B. kann dies bei einem elektrischen Schließsystem verwendet werden, um zu prüfen, ob die Botschaft, die Tür zu öffnen, vom Eigentümer oder von einem Einbrecher stammt. Diese Überprüfung der Autorisierung führt zu einer Verdopplung der Transaktionen. Autorisierte Botschaften erfordern 4 Transaktionen (die anderen nur 2: update und Bestätigung). Dies beansprucht natürlich wieder die Rechenzeit und die Kapazität. Einrichten eines Knoten mit autorisierten Netzwerkvariablen Die Netzwerkvariable wird mittels des reservierter Worte authenticated oder kurz auth in den Verbindungs-Informationen deklariert. bind_info ([authenticated | nonauthenticated] [(config | nonconfig)]) zum Beispiel: network output boolean bind_info(auth(nonconfig)) nv_safe_lock; Das Aufnehmen des Wortes config hat zur Folge, daß das Management Network Tool den Autorisierungs-Status dieser Netzwerkvariablen ändern kann, nachdem der Knoten installiert wurde. Wird dagegen nonconfig gesetzt, ist ein Ändern mittels nv_safe_lock nicht möglich. Spezifizieren des Autorisierungsschlüssels Dies wird mittels eine hex-Zahl in der Workbench unter "App Node / Node Specs" vorgenommen. Gehört der Knoten zu 2 Domänen, muß für jede Domäne ein Schlüssel angegeben werden. Alle Knoten, die die autorisierte Variable lesen oder schreiben, müssen denselben Schlüssel besitzen. Der Schlüssel ist 48 bit lang. Das Network Management Tool kann die Schlüssel mittels eines network management commands ändern. Arbeitsweise bei der Übertragung - Knoten A schickt ein Update an eine Netzwerkvariablen, die in Knoten B mittels Autorisierung deklariert ist.

Empfängt A nicht die Rückfrage von B, wird die Initialisierung wiederholt.

Page 18: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

18

- Knoten B generiert eine 64 bit Zufallszahl und schickt diese zusammen mit anderen Daten in einem Forderungspaket an Knoten A. Die Zufallszahl wird mit einem Kodierungsalgorithmus erzeugt, in dem der 48 bit lange Zugriffsschlüssel transformiert wird.

- Knoten A nutzt denselben Kodierungsalgorithmus, um eine Zufallszahl seines Schlüssels und den Daten von B zu erzeugen. Knoten A sendet diese Transformation an B zurück.

- Knoten B vergleicht die Transformation. Wenn eine Gleichheit besteht, ist die Identität des Senders (Knoten A) geprüft. Knoten B führt nun die geforderte Aktion aus und schickt eine Bestätigung an A. Waren die Schlüssel nicht gleich, wird die Aktion nicht ausgeführt, es wird ein Fehler in die Fehlertabelle eingetragen.

War bei einer Botschaft das Prüfen der Autorisierung bereits erfolgreich, dann wird bei Verlust der Bestätigung und dem nachfolgendem Wiederholen der Botschaft die Autorisierung nicht nochmals geprüft, die Aktion wird sofort gestartet. Ist ein Ausgang mit mehreren Lese-Knoten verbunden, die eine Autorisierung fordern, dann wird die 64-bit-Zufallszahl von jedem Lese-Knoten erzeugt. Der Schreib-Knoten muß demzufolge für jeden Leseknoten die Zufallszahl transformieren und zurückschicken. => Bemerkung zur Sicherheit des Schlüsselwortes: Bei der Installation sollte der Knoten direkt mit dem Network Management Tool verbunden werden und damit der Schlüssel installiert werden. Der Schlüssel wird nicht über das Netz geschickt und kann demzufolge nicht von Fremdpersonen gelesen werden. Wird der Schlüssel später über das Netz verändert, so wird nur eine Zahl geschickt, die zum bereits vorhandenen Schlüssel addiert wird.

Page 19: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

19

6. Kommunikation mittels expliziter Botschaften Zur Übermittlung von Nachrichten zwischen den Knoten kann man nicht nur die Netzwerkvariablen verwenden, der Datenaustausch über explizite Botschaften ist ebenfalls möglich. Explizite Botschaften haben folgende Eigenschaften: - die Größe der Datenfelder ist variabel - sie erfordern einen Anfrage-Antwort-Mechanismus, der komplexer als beim Polling ist - sie stellen die Basis für entfernte Prozeduraufrufe dar, d.h. ein Knoten kann eine Aktion auf einem anderen

Knoten aufrufen - es werden komplexere Methode als bei Netzwerkvariablen benötigt - sie benötigen weniger EEPROM-Speicher als Netzwerkvariablen, dafür mehr Platz für den Programmcode. 6.1. Schichten der NEURON Chip Software Sie besteht aus 3 Schichten: - der Applications-Schicht einschließlich Scheduler - der Netzwerk-Schicht - der Media-Access-Control-Schicht (MAC) Jede Schicht korrespondiert mit ein oder mehreren Schichten über das LONTALK-Protokoll und wird von einem separatem Prozessor kontrolliert. Nur die Applicationsschicht kann programmiert werden. Es besteht außerdem Zugang zu einigen Informationen der Netzwerkschicht.

6.2. Allgemeines zu Botschaften Konstruieren einer Botschaft Das zu konstruierende Botschaftsobjekt trägt den vordefinierten Namen msg_out. Zu einer bestimmten Zeit sind nur eine eingehende und eine ausgehende Botschaft verfügbar. Paralleles Versenden von 2 Botschaften ist also nicht möglich. Definition des msg_out-Objekts: typedef enum {FALSE, TRUE} boolean; typedef enum {ACKD, UNACKD_RPT, UNACKD, REQUEST} service_type; struct { boolean priority_on; // TRUE, wenn Priority-Botschaft, Standard FALSE msg_tag tag; // ID-Nummer, notwendig int code; // Code der Botschaft, notwendig int data[MAXDATA]; // Daten der Botschaft, Standard none boolean authenticated // TRUE, wenn Autorisierung gefordert, Standard FALSE service_type service; // Service-Typ, Standard ACKD msg_out_addr dest_addr // optional, siehe msg_addr.h } msg_out Zur Erläuterung der Angaben:

Page 20: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

20

priority_on: TRUE setzen, wenn die Botschaft als Priority verschickt werden soll. tag: wird vom Nutzer spezifiziert als Identifikation der Botschaft. Es ist notwendig, bei jedem Versenden einer

Botschaft tag einen Wert zuzuweisen! Ist dieser Wert einmal zugewiesen, kann die Botschaft nur noch geschickt oder gelöscht werden.Die Variable wird für die Adressierung und für das Verbinden des Erfolgs-Ereignisse und der Antwort.

code: numerischer Kode der Botschaft. Siehe Punkt Deklaration der Botschafts-Kodes int data[MAXDATA]: Array, das die zu sendenden Daten aufnimmt authenticated: TRUE setzen, wenn Autorisierung gefordert wird. service: ACKD - Bestätigung mit Wiederholungs-Funktion

UNACKD - keine Bestätigung UNACKD_RPT - keine Bestätigung für Wiederholungen (Botschaft wird mehrmals gesendet) REQUEST - Anfrage/Antwort - Funktion. Der Empfänger-Knoten schickt eine Antwort zum Sende-Knoten. Der Sende-Knoten verarbeitet die Antwort. Siehe spätere Kapitel für eine genauere Beschreibung.

dest_addr: Dieses Feld ist optional. Wenn die Botschaft mittels explizierter Adressierung verschickt wird, wird die Botschaft mit diesem Wert verbunden.

Deklaration der Botschafts-Identifikations-Nummern (Message Tags) In der dieser Deklaration können optional Verbindungsinformationen angegeben werden. msg_tag [connection-info] tag-identifier [,tag-identifier...]; connection-info wird in der Form bind_info (options) angegeben. Für options kann stehen: nonbind: Botschaft, die keine Adreßinformationen trägt und demzufolge nicht in der Adreßtafel steht. Kann für

optimalere Nutzung der Resourcen genutzt werden, wenn die Adressierung nicht erforderlich ist. rate_est (const_ausdruck):

geschätzte Verzögerungsrate in Zehntelsekunden, die die Botschafts für ihre Versendung erwartet. (Wert zwischen 0 und 18780).

Max_rate_est(const_Ausdruck): geschätzte maximale Rate in Zehntelsekunden, die die Botschaft für ihre Versendung erwartet. (0-18780).

tag_identifier: NEURON C Identifikator für message tag. Botschafts-Kodes Für die Nutzung durch die Applikation stehen die Werte 0-62 und 64-78 zur Verfügung. Der untere Bereich wird für applikationsspezifische Botschaften, der obere Bereich für Übergänge zu anderen Netzwerken genutzt. Nummer 63 wird nur von Antworten genutzt um anzuzeigen, daß der Empfänger im Zustand offline ist und nicht anworten kann. Für Netzwerk-Diagnose werden die Nummern 80 bis 95, für Netzwerk-Management die Nummern 96 bis 127, für Netzwerkvariablen 128 bis 255 verwendet. Beispiel: msg_tag motor; #define MOTOR_ON 0 #define ON_FULL 100 msg_out = motor; msg_out.code = MOTOR_ON; msg_out.data[0] = ON_FULL; Block Transfer von Daten Hier wird die memcpy-Funktion, die Adresse des msg_out-Objekts bzw. resp_out-Objekts (siehe auf folgenden Seiten) benutzt Syntax der memcpy-Funktion: memcpy(msg_out.data &s, sizeof(s));

Page 21: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

21

msg_out.data: Zielort der Kopie. Dies kann auch ein spezielles Feld des Botschaftsobjekts sein (z.B.

msg_out.data[3]) &s: Zeiger auf eine Struktur, die die zu kopierenden Daten enthalten. Das Feld kann ein Zeiger, ein Array, ein

Zeiger auf ein Element eines Arrays (&a[5]) sein. sizeof(s): Größe der Struktur s. Diese Funktion kann auch für msg_in und resp_in Objekte verwendet werden: memcpy(&s, msg_in.data, sizeof(s)) Dabei ist &s wieder ein Zeiger auf den Zielpuffer, msg_in.data sind die Quelldaten, sizeof(s) die Größe des Zielpuffers. Beispiel: msg_tag motor; #define MOTOR_ON 0 typedef enum { MOTOR_FWD, MOTOR_REV } motor_dir; struct { long motor_speed; motor_dir motor_direction; int motor_ramp_up_rate; } motor_on_message; msg_out.tag = motor; msg_out.code = MOTOR_ON motor_on_message.motor_direction = MOTOR_FWD; motor_on_message.motor_speed = 500 motor_on_message.motor_ramp_up_rate = 100 memcpy(msg_out.data, &motor_on_message, sizeof(motor_on_message)); Senden der Botschaft

Nachdem alle Daten im msg_out-Objekt eingetragen wurden, wird dieses Objekt mittels msg_send(); geschickt. Das Senden des Objekts muß vor dem Ende eines Tasks erfolgen, da am Taskende das msg_out-Objekt automatisch gelöscht wird. Soll das msg_out-Objekt von Taskende gelöscht werden, kann dies mittels der Funktion msg_cancel() erfolgen. msg_tag motor; #define MOTOR_ON 0 #define ON_FULL 100

Page 22: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

22

msg_out = motor; msg_out.code = MOTOR_ON; msg_out.data[0] = ON_FULL; msg_send(); Empfang einer Botschaft Dazu existieren 2 Möglichkeiten: (1) Bei jedem Eingehen einer Botschaft gilt: msg_arrives = TRUE. msg_arrives kann durch einen Botschafts-Kode qualifiziert werden. Nichtqualifizierte msg_arrives-Ereignisse werden beim Eingang jeder Botschaft wahr. #pragma scheduler_reset when (msg_arrives(1)) //Botschaft mit Message-Code1 { io_out(sprinkler, ON); } when (msg_arrives(2)) { io_out(sprinkler, OFF); } when (msg_arrives) //Standard-Fall für alle unerwarteten Botschaften. { } (2) Die Abfrage erfolgt durch die msg_receive()-Funktion. boolean msg_receive(void); Ist keine Nachricht eingegangen, wird diese Zeile übergangen, er wird nicht gewartet. Diese Funktion wird benötigt, wenn in einem Task mehr als eine Botschaft erwartet wird, z.B im Bypass-Modus. Format der eingehenden Botschaft Alle Botschaften stehen nach Eingang in einem msg_in-Objekt zur Verfügung. typedef enum {FALSE, TRUE} boolean; typedef enum {ACKD, UNACKD_RPT, UNACKD, REQUEST} service_type; struct { int code; //Botschafts-Kode int len; //Länge der Daten int data[MAXDATA]; //Daten boolean authenticated; //TRUE wenn autorisiert msg_in_addr addr //siehe msg_addr.h include-Datei } msg_in; code: numerischer Kode siehe Erläuterung msg_out. len: Länge der Daten der Botschaft data: Daten der Botschaft, ist nur belegt, wenn len>0. MAXDATA = app_buf_in_size - 6 oder MAXDATA =

app_buf_in_size - 17 (für explizite Adressierung). authenticated: TRUE, wenn autorisiert. service: ACKD - Bestätigung mit Wiederholungs-Funktion

UNACKD - keine Bestätigung UNACKD_RPT - keine Bestätigung für Wiederholungen (Botschaft wird mehrmals gesendet) REQUEST - Anfrage/Antwort - Funktion. Der Empfänger-Knoten schickt eine Antwort zum Sende-Knoten. Der Sende-Knoten verarbeitet die Antwort. Siehe spätere Kapitel für eine genauere Beschreibung.

addr: optional.Wird Bestimmen der Quelle und des Bestimmungsorts der Botschaft verwendet.

Page 23: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

23

"Default"-When-Fälle Jedes Programm, das Nachrichten erhält, muß auch einen when-Zweig enthalten, der unerwünschte Nachrichten behandelt. when (msg_arrives) {...}; Ist dieser Zweig nicht vorhanden, würde eine Nachricht, die nicht abgefordert wird, ständig am Anfang der Warteschlange stehen und die nachfolgenden Botschaften blockieren. Ist ein das Programm in einem Knoten nicht für den Botschafts-Empfang ausgelegt (es existiert kein msg_arrives und kein msg_receive()), löscht der Scheduler selbst eingehende Botschaften. Beispiel: //Lampen-Beispiel, das explizite Botschaften verwendet #pragma scheduler_reset #define LAMP_ON 1 #define LAMP_OFF 2 #define OFF 0 #define ON 1 IO_0 output bit io_lamp_control when (msg_arrives(LAMP_ON)) { //Einschalten io_out(io_lamp_control, ON); } when (msg_arrives(LAMP_OFF) { //Ausschalten io_out (io_lamp_control, OFF); } when (msg_arrives ) { } Programm für den Kontroll-Knoten: #define LAMP_ON 1 #define LAMP_OFF 2 IO_4 input bit io_switch_in; msg_tag TAG_OUT; when (reset) { io_change_init(io_switch_in); } when(io_changes(io_swich_in)) { msg_out.code = (input_value == ON) ? LAMP_ON : LAMP_OFF; msg_out.tag = TAG_OUT; msg_send(); } Verbinden der Botschafts-Identifikations-Kennzeichen (Message-Tags) Jeder Knoten besitzt ein msg_in-Kennzeichen. Dieses muß beim Senden angegeben werden, damit der Empfänger ermittelt werden kann. Die Identifikationskennzeichen werden mit msg_in verbunden, beim Senden wird tag-out mit dem msg_in Kennzeichen verbunden.

Page 24: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

24

ACKD-Service Wird eine Botschaft über den ACKD-Service verschickt, wie oben beschrieben, so muß das Bestätigungen nicht von der Applikationsschicht übernommen werden. Es braucht daher nicht im Programm beachtet werden. 6.3. Fertig_Ereignisse für Botschaften msg_completes [(msg_tag_name)] wird TRUE, wenn Bearbeitung einer ausgehenden Nachricht beendet ist. msg_succeeds [(msg_tag_name)] wird TRUE, wenn das Verschicken der Botschaft erfolgreich war. msg_fails [(msg_tag_name)] wird TRUE, wenn das Senden einer Botschaft fehlerhaft war. Regeln für das Bearbeiten von Fertig-Ereignissen für Botschaften (1) msg_succeeds und msg_fails müssen immer paarweise verwendet werden.

msg_completes kann auch allein stehen. (2) wenn ein Fertig-Ereignis für eine spezielle Botschaft (Identifikations-Nummer = Tag) verwendet wird, dann

muß jedes Fertig-Ereignis für diese Botschaft bearbeitet werden. Im Gegensatz dazu ist es nicht notwendig, für alle anderen Botschaften (andere Identifikations-Nummer = Tag) die Fertig-Ereignisse zu testen.

(3) Wird ein unqualifiziertes Fertig-Ereignis verwendet, so müssen auch alle Botschaften nach dem Senden auf Fertig-Ereignisse geprüft werden. Dies ist entweder über unqualifizierte Tests der anderen Fertig_Ereignisse oder über qualifizierte Ereignisse nach jedem Senden einer Botschaft realisierbar.

int failures[2], success; msg_tag TAG1, TAG2; when (io_changes(toggle)) { msg_out.tag = TAG1; msg_out.code = TOGGLE_STATE; msg_out.data[0] = input_value; msg_send(); msg_out.tag = TAG2; msg_out.code = TOGGLE_STATE; msg_out.data[0] = input_value; msg_send(); } when (msg_fails(TAG1)) { failures[0]++; } when (msg_fails(TAG2)) { failures[1]++; }

Page 25: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

25

when (msg_succeeds) //für jede Botschaft { success++; } 6.4. Botschaften und der Preemption Modus Das System geht in den Preemption Modus, wenn für eine zu verschickende Botschaft kein Puffer frei ist. Das Programm wartet in diesem Fall und behandelt nur noch Fertig-Ereignisse, ankommende Botschaften und Antworten. Der Watchtimer wird während dieser Zeit ständig aktualisiert, so daß die zu versendende Botschaft nicht durch das Ende des Tasks verlorengeht. Wenn sich das System im Preemption Modus befindet und eine weitere Botschaft verschickt werden soll (z.B. in einem when ( msg_completes )-Zweig), wird der entsprechende Knoten zurückgesetzt. when (TOGGLE_ON) { //erstellen der Botschaft und verschicken } when (msg_completes) { msg_out.tag = t; msg_out.code = 1; } Richtig: msg_send() wird nicht in einem when ( msg_completes )-Zweig verwendet. 6.5. Asynchrone und direkte Ereignisverarbeitung Der Test von Ereignissen in einem when-Task in asynchron. Direkte Ereignisverarbeitung bedeutet: Der Test findet innerhalb eines Tasks mittels if oder while statt. Man soll kein msg_completes-Ereignisse in einem Task verwenden, der mit eine msg_completes-Ereigniszweig verbunden ist: when (msg_completes) { post_events(); if msg_completes) x = 4; //nicht empfehlenswert } Asynchrone und direkte Ereignisverarbeitung in einem Programm ist möglich. Asynchrone Ereignisverarbeitung ist typischer, da die Programmgröße in diesem Fall kleiner ist. Vor dem Wechsel von asynchroner zu direkter Verarbeitung ist es notwendig, die Funktion flush_wait() aufzurufen. Dieser Aufruf sichert, daß noch alle ausstehenden Fertig-Ereignisse und Antworten vor dem Umschalten in die direkte Verarbeitung bearbeitet werden. msg_tag motor; #define MOTOR_ON 0 when (x==3) { flush.wait(); msg_out.tag = motor; msg_out.code = MOTOR_ON; msg_send(); while (!msg_succeeds(motor)) { post_events(); if (msg_fails(motor)) node_reset(); }

Page 26: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

26

} 6.7. Anfrage - Antwort - Mechanismus (Request - Response) Eine Applikation auf einem Knoten fordert Daten von einer Applikation auf einem anderen Knoten an. Diese Funktion wird automatisch benutzt, wenn mit polled input Variablen gearbeitet wird. Man kann diesen Mechanismus auch für explizite Botschaften benutzten. Es gibt einen wichtigen Unterschied zu polled deklarierten Netzwerkvariablen: Bei Netzwerkvariablen kann man nicht explizit im Programm auf eine Anfrage vom Leseknoten reagieren. Bei Botschaften vom Request-Response-Typ muß man auf eine Anfrage direkt reagieren, d.h. den Programmcode für eine Anfrage selbst schreiben. Wo liegen die Vorteile? Ein Beispiel: Ein Lüftermotor soll angeschaltet werden. Hier muß man sichergehen, daß der Motor auch läuft. Man schickt also an diesen Knoten eine Botschaft mit dem Request-Service. Der Knoten muß nun auf diese Botschaft antworten. Er kann also ein OK oder eine Fehlermeldung zurücksenden. Der Sender erhält also immer eine Antwort vom Empfänger-Knoten, ob der Lüftermotor funktioniert oder nicht. Eine Anfrage kann dabei den vorbereiteten Request-Service des Neuron Chip benutzten. Die Anfrage fordert vom Antwortknoten, die Variable zur Zeit der Anfrage zu liefern. Es werden Funktionen analog zu den oben beschriebenen Botschaftsfunktionen genutzt. msg_tag motor; #define MOTOR_STATE 1 when (io_changes(switch1) to 2) { msg_out.tag = motor; msg_out.service = REQUEST; msg_out.code = MOTOR_STATE; msg_send(); } Das Programm auf dem Empfängerknoten empfängt die Anfrage in einem when-Zweig oder über eine msg_receive() Funktion, der Knoten muß darauf antworten. Erstellen einer Antwort Eine Antwort ist nicht gleichzusetzen mit einer Bestätigung! Das ausgehende Objekt heißt resp_out. Die Antwort übernimmt dabei die Priorität und die Autorisierungskennzeichen der Anfrage. Die Botschafts-Identifikation (message tag) ist nicht notwendig, da die Antwort automatisch zum anfragenden Knoten zurückgeschickt wird. Definition resp_out: struct { int code; int data[MAXDATA]; } resp_out; code: numerischer Kode. siehe Erläuterungen vorhergehende Seiten. data: Daten der Botschaft. MAXDATA ist Funktion von app_buf_in_size. Siehe vorhergehende Erläuterungen

msg_in. Senden einer Antwort Das erstellte resp_out-Objekt wird mit der Funktion resp_send() verschickt. Es ist zu beachten, daß die Antwort in derselben critical section geschickt wird, in der die Anfrage eintraf. Während dieser Zeit können keine weiteren Anfragen oder Antworten bearbeitet werden. Empfangen einer Antwort (1) Mit Hilfe des resp_arrives - Ereignisses:

Page 27: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

27

when ( resp_arrives [(msg-tag-name)] ) (2) Mittels der Funktion resp_receives(): boolean resp_receives(void); BEACHTE: Die Antwort wird am Ende des Tasks, der die Antwort erhielt, verworfen. Format der Antwort Nach Eingang der Antwort steht ein resp_in-Objekt zur Verfügung, das die Daten enthält. struct { int code; int len; int data[MAXDATA]; resp_in_addr addr; } resp_in; code: Numerischer Kode der Botschaft len: Länge der Daten. data: Daten der Botschaft. siehe MAXDATA Erläuterungen in msg_in. addr: optional Beispiel für Anfrage-Knoten: Erstellen und Senden der Anfrage - asynchroner Empfang der Antwort when (io_changes(toggle)) { msg_out.tag = TAG1 msg_out.code = 1; //code für Antwortknoten wichtig msg_send(); } when (msg_arrives(TAG1)) { if (resp_in.code == OK) process_response (resp_in.data[0]); } Beispiel für den Antwortknoten: Erstellen einer Antwort auf eine Anfrage when (msg_arrives (1)) //Antwort auf Botschaft mit Code 1 { int x, y; x = msg_in.data[0]; y = get_response(x); resp_out.code = OK; //Botschaft existiert ab hier nicht mehr resp_out.data[0] = y; resp_send(); } Beispiel für Anfrage-Knoten: Erstellen und Senden der Anfrage und direkter Empfang int x; msg_tag motor; #define MOTOR_ON 0 #define DO_MOTOR_ON 3 when (command == DO_MOTOR_ON) { msg_out.tag = motor; msg_out.code = MOTOR_ON; msg_out.service = REQUEST;

Page 28: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

28

msg_send(); //Warten auf Antwort while (!msg_succeeds(motor)) { post_events(); if (msg_fails(motor)) node_reset(); else if (resp_arrives(motor)) { x = x + resp_in.data[0]; resp_free(); } } } Vergleich der resp_arrives / msg_succeeds-Ereignisse Es können sowohl resp_arrives als auch die Fertig-Ereignisse (msg_succeeds, msg_completes, msg_fails) verwendet werden, da sie unterschiedliche Informationen liefern. Als Beispiel dient eine Anfrage, die an 6 Knoten gestellt wird. Drei Knoten empfangen die Anfrage, die anderen drei nicht. Daraus ergibt sich folgendes Verhalten: - resp_arrives wird 3 Mal TRUE - msg_arrives wird nie TRUE, da nicht alle Anfrage ankamen - msg_fails wird TRUE, wenn die Antworten nicht in der vorgesehenen Zeit eintreffen. Die Antworten treffen dabei immer vor den Fertig-Ereignissen (msg_succeeds, msg_completes, msg_fails) für die Botschaften ein. 6.8. Puffer Die Anzahl der E/A-Puffer wird während der Übersetzungszeit festgesetzt. Folgende Belegung ist als Standard vorgesehen: - 2 priority output - 2 nonpriority output - 2 input Für eine effiziente Verarbeitung von Antworten sollte die Anzahl der Puffer gleich der Anzahl der eingehenden Antworten sein. Ist dies nicht der Fall, kann es passieren, daß einige Antworten nie ankommen, da die Antworten in der gleichen critical section ankommen müssen, in der die Anfrage geschickt wurde (s.o.). Stehen nicht ausreichend Puffer zur Verfügung, kommt es zu einer Zeitüberschreitung, die das Ende der critical section bedeutet. Es ist zu beachten, daß Puffer nicht nur für eingehende Antworten, sondern auch für eingehende Botschaften genutzt werden. Bei der direkten Ereignisverarbeitung ist dafür zu sorgen, daß die Puffer wieder frei werden, indem alle Botschaften und Antworten abgefragt werden. Allokieren von Puffern Puffer werden normalerweise automatisch vom Scheduler angefordert und nach Beenden einer critical section wieder freigegeben. Puffer können aber auch explizit allokiert werden: boolean msg_alloc(void) boolean msg_alloc_priority(void) void msg_free(void) Priority-Puffer haben bessere Aussichten, im Netz schnell verschickt zu werden als nonpriority-Puffer. Die beiden Funktionen msg_alloc und msg_alloc_priority liefern TRUE zurück, wenn ein msg_out-Objekt zur Verfügung steht. Über die Compiler-Optionen #pragma... kann die maximale Anzahl von Puffern festgelegt werden (siehe dort). Die Funktion msg_free löscht ein msg_in-Objekt.

Page 29: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

29

Wenn in ein msg_out-Objekt ein Wert eingetragen wird, aber kein msg_out-Objekt zur Verfügung steht (d.h. es ist kein Puffer frei), geht das System in den Preemption Modus. Um dies zu vermeiden, ist es nützlich, die oben genannten Funktionen zu benutzen, da sie beim Fehlen von freien Puffern nur FALSE zurückliefern, aber nicht in den Preemption Modus übergehen. BEACHTE: Ein Puffer, der über msg_alloc allokiert wurde, kann nicht mittels msg_free wieder freigegeben werden. Nur über die Funktion msg_send kann der Puffer wieder freigegeben werden. msg_free kann nur Puffer freigeben, die durch ein msg_in-Objekt als Folge von msg_receive belegt wurden. Analog dazu funktionieren auch die beiden Funktionen boolean resp_alloc(void) void resp-free(void) die für den Anfrage-Antwort-Mechanismus verwendet werden können. msg_tag motor1; msg_tag motor2; #define MOTOR_ON 0 when (x == 2) { if (msg_alloc() == FALSE) return; msg_out.tag = motor1; msg_out.code = MOTOR_ON; msg_send(); if (msg_alloc() == FALSE) return; msg_out.tag = motor2; msg_out.code = MOTOR_ON; msg_send(); }

Page 30: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

30

7. Bemerkungen zum Speicher-Management 7.1. Adreß-Tabellen #pragma num_addr_table_entries n Die Adreßtabelle enthält eine Liste von Netzwerkadressen. Jeder Eintrag belegt 5 byte im EEPROM. Die maximale Anzahl für einen Knoten ist gleich der Anzahl der Verbindungen, die dieser Knoten zu anderen Knoten besitzt. 7.2. Allokieren von Puffern Die Puffergröße für explizite Botschaften muß für die längste eingehende Botschaft ausreichend sein. - Applikations-Puffer-Größe: Botschaftsgröße + 5 byte system overhead - Netzwerk-Puffer-Größe: Botschaftsgröße + 6 byte system overhead + 20 byte protocol overhead Ist die Größe der Puffer nicht ausreichend bemessen, entstehen während der Laufzeit zu den Fehlermeldungen APP_BUF_TOO_SMALL und NET_BUF_TOO_SMALL. Ausgangs-Applikations-Puffer #pragma app_buf_out_size n Für ausgehende priority und nonpriority Botschaften verwenden. #pragma app_buf_out_count n Anzahl der Applikations-Puffer für ausgehende explizite nonpriority Botschaften und nonpriority Netzwerkvariablen. #pragma app_buf_out_priority_count n Anzahl der Applikations-Puffer für ausgehende explizite priority Botschaften und nonpriority Netzwerkvariablen. Ausgangs-Netzwerk-Puffer #pragma net_buf_out_size n Netzwerkpuffergröße für ausgehende nonpriority und priority explizite Botschaften und Netzwerkvariabeln. Die Größe n sollte größer als 34 sein. #pragma net_buf_out_count n Anzahl der Netzwerk-Puffer für ausgehende explizite nonpriority Botschaften und nonpriority Netzwerkvariablen. #pragma net_buf_out_priority_count n Anzahl der Netzwerk-Puffer für ausgehende explizite priority Botschaften und nonpriority Netzwerkvariablen. Eingehende-Netzwerk-Puffer #pragma net_buf_in_size n Größe der Netzwerkpuffer für eingehende explizite Botschaften und Netzwerkvariablen. Die Größe n sollte größer als 50 sein.

Page 31: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

31

#pragma net_buf_in_count n Anzahl der Netzwerkpuffer für eingehende explizite Botschaften und Netzwerkvariablen. Eingangs-Applikations-Puffer #pragma app_buf_in_size n Größe der Applikationspuffer für eingehende explizite Botschaften und Netzwerkvariablen. Die Größe n sollte größer als 22 sein. #pragma app_buf_in_size n Anzahl der Applikationspuffer für eingehende explizite Botschaften und Netzwerkvariablen. Beachte dazu Tabellen 6-1 und 6-2 7.3. Anzahl der Empfangs-Transaktionen Damit kann die Anzahl der Einträge eines Arrays festgesetzt werden, die gleichzeitig bedient werden können. #pragma receive_trans_count n n ist die Anzahl der Einträge im Receive Transaction Array.

Page 32: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

32

8. Verschiedenes 8.1. Scheduler-Reset-Mechanismus #pragma scheduler_reset Das Verwenden dieser Zeile im Programm schaltet den Mechnismus ein. Der round-robin-Teil des Schedulers wird auf eine reguläre when-Abfrage gesetzt, wenn folgendes passiert: - eine aktualisierte Netzwerkvariable erscheint am Kopf der Warteschlange - ein Zeitgeber ist abgelaufen - eine neue Botschaft steht am Kopf der Warteschlange 8.2. Der Watchdog-Timer Der Watchdog-Timer verhindert, daß ein Task unendlich lange läuft und demzufolge die Verarbeitung anderer Botschaften und Ereignisse verhindert. Ist es notwendig, einen sehr langen Task zu verwenden, der die vorgesehene Zeit überschreitet (0,84 bis 1,68 Sekunden), so wird dieser Task auch abgebrochen, obwohl er einwandfrei funktioniert. Um dies zu verhindern, muß der Watchdog-Timer rechtzeitig zurückgesetzt werden: watchdog_update() 8.3. Zusätzliche vordefinierte Ereignisse vom Netzwerk Management Tool offline Ein offline management command ereignet sich, wenn es vom Netzwerk Management Tool verschickt wurde. Ist der Knoten danach offline geschaltet, empfängt er nur noch Management commands. online Ein online management command ereignet sich, wenn es vom Netzwerk Management Tool verschickt wurde. wink Das wink-Ereignis ist ein spezielles Kommando, das vom Netzwerk Management Tool verschickt werden kann. Im Programm ist mit diesen Ereignissen folgendermaßen umzugehen: when ( offline ) {...} when ( online ) {...} 8.4. Fehler-Behandlung Fehler können folgendermaßen behandelt werden: - Zurücksetzen des Knotens und Neustart der Applikation - Eintrag des Fehlers in die Fehlertabelle und Fortsetzung des Programms (1) Zurücksetzen des Knotens Die Funktion node_reset() wird aufgerufen. Dies bewirkt, daß alle 3 Prozesse zurückgesetzt werden (siehe Schichtmodell des NEURON Chips). Nach dem Zurücksetzen wird die Initialisierungs-Sequenz ausgeführt. Alle Zustandsinformationen, die nicht im EEPROM gespeichert sind, gehen verloren. Dabei kann es zu Problemen mit dem Netzwerk-Prozessor kommen. Nachrichten können doppelt entgegengenommen werden oder verlorengehen.

Page 33: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

33

(2) Neutstart der Applikation Aufruf über die Funktion application_restart(). In diesem Fall wird nur der Applikations-Prozessor neu gestartet. Nach dem Neustart werden alle Zeitgeber zurückgesetzt, E/A-Objekte, Netzwerkvariablen und statische Variablen werden initialisiert, danach wird der when(reset)-Zweig aufgerufen. Statusinformationen des Netzwerkes gehen nicht verloren, da die beiden anderen Prozessoren weiterlaufen. (3) Eintragen von Programmfehlern In diesem Fall muß die Funktion error_log() aufgerufen werden. Diese Funktion trägt eine Fehlernummer zwischen 1 und 127 in die Fehlertabelle ein. Die Fehlernummer befindet sich also in einem speziell dafür vorgesehenen EEPROM-Bereich. Die Fehlertabelle kann durch das Management Tool gelesen werden. (4) System-Fehler Programmierfehler, Netzwerkfehler, Widersprüche werden genauso wie Programmfehler in die Fehlertabelle eingetragen. Zugang zum Fehlerstatus eines Knotens Das Programm hat einen lokalen Zugang zum Fehlerstatus, das Management Tool hat diesen Zugang ebenfalls. Die Statusinformationen sind in einer Statusstruktur gespeichert. Mit folgender Funktion kann sie gelesen werden: void retrieve_status(statusstruct * status_p) Die Funktion clear_status() löscht die Statusinformationen

Page 34: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

34

9. Komplexes Beispiel Hier nun ein Beispielprogramm, in dem viele der vorher beschriebenen Netzwerkfunktionen angewandt wurden. Das Programm stellt einen Flugrechner für Segelflugzeuge dar, dessen einzelne Komponenten Messung, Steuerung, Rechnung und Ausgabe auf verschiedenen Knoten laufen. Die Knoten tauschen untereinander Daten aus. Doch zuerst das Konzept:

Der Sensorknoten erfaßt die Meßwerte und bildet stets über die letzten 8 Meßwerte einen Mittelwert. Mit diesem Mittelwert ist die Variable Messwert ständig belegt. Da diese Variable als polled deklariert ist, wird einen Änderung dieser nicht über das Netz geschickt. Hierbei ist zu bedenken, daß im Programm dieses Knotens nicht auf eine Abfrage des Messwertes reagiert werden kann, so daß der Mittelwert ständig gebildet werden muß. Man kann nicht programmieren, was passieren soll, wenn der Steuerknoten den Wert mittels poll abfragt. Der Quelltext enthält Befehle, die für die Erfassung des Meßwertes bestimmt sind. Diese werden hier nicht erklärt. 1) /* Quelltext des Meßknotens */ 2) #include <SNVT_lev.h> 3) IO_0 output bit pin0; 4) IO_1 output bit pin1; 5) IO_4 input period mux clock(7) io_switch_4; 6) mtimer repeating MessTimer; /*Millisekunden-Timer*/

Page 35: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

35

7) network output polled int Messwert; /*OutputVariable Polled*/ 8) int MessFeld[8]; 9) int MessZaehler; 10) long int Summe; 11) int nv_value1; 12) when ( reset ) 13) { 14) int i; 15) io_out (pin0,1); io_out (pin1,0); 16) MessTimer = 250; /*aller 250ms auslösen*/ 17) MessZaehler = 0; 18) for (i = 0; i < 8; i++) MessFeld[i] = 0; 19) } 20) when ( timer_expires(MessTimer) ) 21) { 22) int i; 23) MessFeld[MessZaehler] = nv_value1; 24) MessZaehler = MessZaehler + 1; 25) if (MessZaehler == 8) MessZaehler = 0; 26) Summe = 0; 27) for (i = 0; i<8; i++) Summe = Summe+MessFeld[i]; 28) Messwert = Summe >> 3; /*Wertzuweisung an Output-

Variable*/ 29) } 30) when (io_update_occurs(io_switch_4)) /*neuer Meßwert liegt an*/ 31) { 32) nv_value1 = -((input_value/3*2)-20); 33) } In Zeile 7) wird die Output-Variable Messwert als polled deklariert, in Zeile 27) wird der Wert dieser Variablen immer wieder neu belegt. Der in Zeile 6) deklariert Messtimer wird in Zeile 16) auf 250 Millisekunden gestellt. Immer wenn diese Variable nach Ablauf der Zeit den Wert TRUE erhält, wird auch das Ereignis timer_expires in Zeile 20) wahr und der neue Wert für Messwert wird berechnet. Der Steuerknoten regelt den Datenfluß zwischen den einzelnen Knoten. Er fragt den Meßwert vom Sensorknoten ab, schickt den Meßwert zum Rechenknoten, empfängt die berechneten Werte und schickt diese, wenn gefordert, an den Ausgabeknoten. Der Steuerknoten fragt den Meßwert vom Sensorknoten mittels poll-Funktion ab. Danach erstellt er eine explizite Botschaft, die er an den Rechenknoten schickt. Der Steuerknoten empfängt eine Botschaft vom Rechenknoten, in der die berechneten Werte als Daten enthalten sind. Diese Daten speichert der Steuerknoten und erstellt bei Anfrage vom Ausgabeknoten eine entsprechene Antwort, in der das gewünschte Datum enthalten ist. 34) /*Quelltext des Steuerknotens*/ 35) #include <SNVT_lev.h> 36) #pragma scheduler_reset 37) network input int Messwert; /*Eingangsvar für Meßwert*/ 38) IO_0 output oneshot Led; 39) stimer repeating Timer1; /*Sekundentimer*/ 40) msg_tag Rechnung; /*MsgTag für Botschaft*/ 41) long int Ausgabefeld[4]; /*Speicher für berechnete Werte*/ 42) when (reset) 43) { 44) Timer1 = 2; /*alle 2 Sekunden auslösen*/ 45) }

Page 36: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

36

46) when ( timer_expires(Timer1)) 47) { 48) poll(Messwert); /*Update der Variable Messwert fordern*/ 49) } 50) /* Update der Variable Messwert ist erfolgt*/ 51) when (nv_update_occurs(Messwert)) 52) { 53) msg_out.tag = Rechnung; /*Vorbereiten einer exp.

Botschaft*/ 54) msg_out.code = 1; 55) msg_out.data[0] = Messwert+25; 56) msg_send(); 57) } 58) /*Fehler bei Schicken der Botschaft mit msg_out.tag = Rechnung*/ 59) when (msg_fails(Rechnung)) 60) { 61) io_out(Led, 10000); 62) } 63) /*Erfolg bei Schicken der Botschaft mit msg_out.tag = Rechnung*/ 64) when (msg_succeeds(Rechnung)) 65) { 66) io_out(Led, 250); 67) } 68) /*eine Botschaft mit msg_in.code = 2 kommt

an*/ 69) when (msg_arrives(2)) 70) { 71) int i; 72) long int ZW; 73) /*Eingehende Werte aus msg_in.data in Array Ausgabefeld*/ 74) memcpy(&Ausgabefeld, msg_in.data, sizeof(Ausgabefeld)); 75) io_out(Led, 250); 76) } 77) /*eine Botschaft mit msg_in.code = 10 kommt

an*/ 78) when (msg_arrives(10)) 79) { 80) int Status; 81) /*da Request vom Ausgabeknoten vorliegt*/ 82) Status = msg_in.data[0]; /*Erstellen der Antwort*/ 83) resp_out.code = 1; 84) /*Kopieren der Daten des Array Ausgabefeld in resp_out.data*/ 85)

memcpy(resp_out.data,&Ausgabefeld[Status],sizeof(Ausgabefeld[Status]));

86) resp_send(); 87) } 88) /*when-Zweig, der alle nicht beantworteten Botschaften

verarbeitet*/ 89) when (msg_arrives) {}; In Zeile 4) wird die Variable Messwert deklariert, die mit der Variable Messwert des Sensorknotens verbunden ist. Die gleichen Namen haben hier keine Bedeutung. Immer wenn Timer1 abgelaufen ist, also den Wert TRUE enthält, wird Zeile 15) ausgeführt. Hier wird der aktuelle Wert von Messwert vom Sensorknoten angefordert.

Page 37: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

37

Der Eingang des neuen Wertes wird dann in Zeile 18) festgestellt. Hier wird danach eine Botschaft erstellt, indem die in Zeile 7) deklarierte Variable Rechnung als Message-Tag verwendet wird. Der Botschafts-Code 1 ist wichtig, da im Knoten, an den die Botschaft geschickt wird, nur ein msg_in-Objekt zur Verfügung steht. Die Unterscheidung zwischen den einzelnen Botschaften erfolgt über msg_in.code (vgl. Zeile 115). In Zeile 69) wird auf das Ereignis Botschaft mit Code = 2 reagiert. Da auch hier nur ein msg_in-Objekt zur Verfügung steht, ist die Unterscheidung nur mittels msg_in.code möglich. Die Botschaft wurde im Rechenknoten Zeile 134)ff erstellt. In Zeile 74) werden die Daten aus dem msg_in-Objekt in das Array Ausgabefeld kopiert. Dabei ist zu beachten, daß beim Erstellen der Botschaft das Array Ergebnisse im Rechenknoten 104) die gleiche Struktur hat wie das Array Ausgabefeld im Steuerknoten, da die memcpy-Funktion eine Binärumwandlung vornimmt und die Struktur der Daten nicht mit übertragen wird. In Zeile 78) wird auf eine eingehende Botschaft mit dem Code 10 reagiert. Da diese Botschaft vom Ausgabeknoten mittels msg_out.service = REQUEST (Zeile 163) erstellt wurde, muß für die Beantwortung ein resp_out-Objekt verwendet werden. Der Rechenknoten nimmt die notwendigen Berechnungen vor. Er speichert dabei alle wichtigen Werte. Er empfängt eine Botschaft vom Steuerknoten und schickt eine Botschaft mit den berechneten Werten an den Steuerknoten zurück. 90) /*Quellcode des Rechenknotens*/ 91) #pragma scheduler_reset 92) #include "polare.h" 93) #define AnzahlSteigWerte 150 94) IO_0 output oneshot Led; 95) msg_tag Zurueck; /*MsgTag für Botschaft*/ 96) long int Hoehe; 97) long int DirektesSteigen; 98) long int far DirektSteigFeld[AnzahlSteigWerte]; 99) long int far MittelSteigFeld[30]; 100) long unsigned SteigZaehler; 101) int MittelZaehler; 102) long int MittelSteigen; 103) long int Sollfahrt; 104) long int Ergebnisse[4]; 105) when ( reset ) 106) { 107) long int i; 108) SteigZaehler = 0; 109) MittelZaehler = 0; 110) Hoehe = 0; 111) for (i = 0; i < AnzahlSteigWerte; i++) DirektSteigFeld[i] = -2; 112) for (i = 0; i < 30; i++) MittelSteigFeld[i] = -2; 113) MittelSteigen = -2; 114) } 115) when (msg_arrives(1)) /*Msg mit Msg.Code = 1 trifft

ein*/ 116) { 117) long int Messwert, i, ZwischenWert; 118) Messwert = msg_in.data[0]; 119) DirektesSteigen = Messwert-25; 120) Hoehe += (200*DirektesSteigen)/36; 121) if (Hoehe < 0) Hoehe = 0; 122) DirektSteigFeld[SteigZaehler] = DirektesSteigen; 123) SteigZaehler = (SteigZaehler+1)%AnzahlSteigWerte; 124) MittelSteigen = 0; 125) for (i=0; i<AnzahlSteigWerte; i++) 126) MittelSteigen += DirektSteigFeld[i]; 127) MittelSteigen = MittelSteigen/AnzahlSteigWerte;

Page 38: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

38

128) MittelSteigFeld[MittelZaehler] = MittelSteigen; 129) MittelZaehler = (MittelZaehler+1)%30; 130) ZwischenWert = DirektesSteigen-MittelSteigen+20; 131) if (ZwischenWert<0) ZwischenWert = 0; 132) if (ZwischenWert>39) ZwischenWert = 39; 133) Sollfahrt = PolareFeld[ZwischenWert]/10; 134) mg_out.tag = Zurueck; /*Erstellen einer

Botschaft*/ 135) mg_out.code = 2; 136) Ergebnisse[0] = Hoehe/10; /*Ausfüllen des Array*/ 137) Ergebnisse[1] = 100*DirektesSteigen/36; 138) Ergebnisse[2] = 100*MittelSteigen/36; 139) Ergebnisse[3] = Sollfahrt; 140) /*Kopieren in msg_out.data*/ 141) memcpy(msg_out.data, &Ergebnisse, sizeof(Ergebnisse)); 142) io_out(Led, 250); 143) msg_send(); 144) } 145) when (msg_arrives) {} Der Rechenknoten berechnet die Werte, die für die Anzeige benötigt werden. Das geschieht in den Zeilen 118) bis 133). Hier ist nur Zeile 118) interessant, da hier der eingehende Meßwert in eine Variable des Rechenknotens übertragen wird. Ab Zeile 135) wird eine Botschaft mit dem Code 2 erstellt, auf die der Steuerknoten reagiert. Erläuterungen siehe oben beim Steuerknoten. Der Ausgabeknoten besitzt einen Schalter, mit dem der Nutzer zwischen den 4 Anzeigewerten umschalten kann. Das LCD kann immer nur einen Wert anzeigen. Der Knoten fordert vom Steuerknoten die aktuellen Daten, wenn eine bestimmte Zeitspanne abgelaufen ist, oder der Nutzer andere Informationen auf dem LCD wünscht. Hierbei wird der Request - Response - Mechanismus verwendet. 146) /*Quelltext für den Ausgabeknoten*/ 147) #pragma scheduler_reset 148) msg_tag AusAnforderung; /*MsgTag für Request Botschaft*/ 149) int AusgabeStatus; 150) stimer repeating AusgabeTimer; /*Sekundentimer*/ 151) long int Ausgabe; 152) IO_4 input bit Schalter; /*Taster für Umschalten*/ 153) when(reset) 154) { 155) AusgabeStatus = 0; 156) AusgabeTimer = 3; /*neue Anzeige alle 3 Sek*/ 157) } 158) void neueAusgabe() /*allgemeine C-Funktion*/ 159) { 160) msg_out.tag = AusAnforderung; /*Erstellen einer Anforderung*/ 161) msg_out.code = 10; 162) msg_out.data[0] = AusgabeStatus; 163) msg_out.service = REQUEST; 164) msg_send(); 165) } 166) when (timer_expires(AusgabeTimer)) 167) { 168) neueAusgabe(); 169) }

Page 39: Neuron C Fibel.doc.pdf.prn - TU Dresden · 3 1. Allgemeines zur Verwendung von Neuron-C Neuron-C ist ein an die speziellen Anforderungen des Neuron-Chips angepaßtes Programmiersystem,

39

170) when (io_changes(Schalter) to 1) 171) { 172) AusgabeStatus = (AusgabeStatus+1)%3; 173) neueAusgabe(); 174) } 175) /*der Rückgabewert der Anforderung kommt an*/ 176) when(resp_arrives(AusAnforderung)) 177) { 178) /*Kopieren der Daten in Array Ausgabe*/ 179) memcpy(&Ausgabe, msg_in.data, sizeof(Ausgabe)); 180) io_out(Led, 1000); 181) } Der Knoten fordert neue Werte an, wenn 3 Sekunden (AusgabeTimer) abgelaufen sind oder wenn der Nutzer den Knopf betätigt und so die Anzeige umschaltet. Dafür wird eine Botschaft AusAnforderung erstellt, bei der der REQUEST-Mechanismus verwendet wird. D.h., der Steuerknoten muß auf diese Botschaft reagieren (78-87). Im Feld msg_out.data wird dabei der Array-Index übergeben, in dem der gewünschte Wert im Array Ausgabefeld im Steuerknoten steht. Es ist wieder zu beachten, daß der Botschafts-Code 10 im Ausgabeknoten und im Steuerknoten übereinstimmen müssen. Die ankommende Antwort auf die Anfrage wird ab Zeile 176) verarbeitet. Die Zuständigkeit wird über den Message-Tag AusAnforderung deklariert. Hier wird nicht der Botschafts-Code benötigt wie bei msg_arrive, sondern die Funktion resp_arrives, da es zu jeder Anfrage (verbunden mit einem Message-Tag) nur eine Antwort geben kann (verbunden mit demselben Message-Tag). Die Variable Schalter wird verwendet, um auf ein Drücken des Schaltknopfes reagieren zu können. Bemerkung: Die Led-Anweisungen wurden nur eingesetzt, um die Transaktionen im Netz auch optisch sichtbar zu machen. Diese Arbeit wurde im Rahmen des Proseminars "Technische Informationssystem" an der TU Dresden / Fakultät Informatik von Alexander Görnitz und Thomas Florstedt erstellt. Aktualisiert am 17.01.2006 an der TU Dresden / Fakultät Informatik