Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.
Kann mir bitte einer sagen, was da nicht stimmt? Ich habe schon die ganze Nacht gesucht. Leider sind da in dem Quelltext von dem TCB_t und ListItem_t so viele #ifdef dass ich nicht weiß, wie ich aus einem StackType_t * ein TCB_t bekomme.
Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.
Kann mir bitte einer sagen, was da nicht stimmt?
Du hast die Netiquette nicht beachtet, längere Quelltexte gehören in den Anhang.
Ich habe schon die
ganze Nacht gesucht. Leider sind da in dem Quelltext von dem TCB_t und
ListItem_t so viele #ifdef dass ich nicht weiß, wie ich aus einem
StackType_t * ein TCB_t bekomme.
Ich auch nicht. Aber für bissel CAN und Solaranlage scheint das hier eine verdammt aufgeblähte Lösung zu sein.
Der Wechselrichter läuft seit einem Jahr ohne Fehler. Problem ist der Batteriespeicher, da kommen ständig Fehlermeldungen wegen der Temperatur und Spannung.
Ich hab da an dem BMS schon einen Monat rumgestellt und es dann aufgegeben. Da braucht es je nach Temperatur und Jahreszeit unterschiedliche MinSOC, MaxSOC und Ladestrom, was das BMS und WR nicht kann.
Also zwei Messwert(sätz)e lesen und anschließend beide ans BMS-Schreiben? Was ist da so arg kompliziert ohne Multitasking?
Wie oft muß das überhaupt passieren, 1/s oder 1/µs?
wenn da irgendwas hängen bleibt.
Meinst Du beim Lesen? Timeout abwarten? k.A. was die sinnvollste Aktion ist, wenn Dir ein Eingabewert fehlt, aber dagegen hilft Dir auch Multitasking nichts, im Gegenteil läufst Du eher Gefahr, nichts mitzubekommen wenn einer der Lese-Tasks dauerhaft hängt und keine Updates liefert.
Ohne Multitasking wird es arg kompliziert, wenn da irgendwas hängen
bleibt.
Mit MT bleibt es vielleicht noch öfter hängen, wenn man da kein Profi ist.
Ich weiß allerdings nicht genau, wo das Problem liegt.
Was soll wo hängen und warum?
Läuft doch alles mit einem Mess-/Aktionstakt > 10 Sekunden, oder?
Wenn eine CAN- oder RS-485-Funktion hängt, kann man das mit einem Watchdog-Timer abfangen. Danach kann man dann eine Ersatzfunktion aufrufen (z. B. das Interface zurücksetzen) und die Aktion beim nächsten Durchlauf erneut versuchen. Bei einer Dauerstörung der Hardware hilft dir MT auch nicht.
also wenn ich TCB_t und ATmega328P lese, dann sagt mir meine innere Stimme das was nicht zusammenpasst oder zusammengewürfelt wurde. TCB_t ist ein struct Datentyp der neueren Controller Serien. Ein ATmega328P hat keine Timer des Typs TCB (oder TCA, TCD) oder dergleichen.
TCB_t
ist ein struct Datentyp der neueren Controller Serien. Ein ATmega328P
hat keine Timer des Typs TCB (oder TCA, TCD) oder dergleichen.
Der hat vor allem kein CAN…
@TO
Der hat auch keinen 3-Byte-PC. Vielleicht hilft das ja weiter. Wobei die Antwort auf die Frage vermutlich „gar nicht“ lautet, und ansonsten RTFM des unbekannten RTOS.
also wenn ich TCB_t und ATmega328P lese, dann sagt mir meine innere
Stimme das was nicht zusammenpasst oder zusammengewürfelt wurde.
TCB soll wohl TaskControlBlock heißen.
Hat also nix mit Timern zu tun.
oder nur um 12 Ecken.
Aha. ;-)
Das könnte zwar wieder eine Abseitsdiskussion werden. Nur wenn ich so rund um die Lib lese wurde diese auch für die neueren Controller angepasst. Wenn TCB_t für was anderes steht, aber für die neuen Controller in deren Headerfile für die Timer schon existiert, dieser Name TCB_t, dann muss das doch früher oder später knallen. Vielleicht knallt das jetzt ausgerechnet beim TO?
Wenn ich der TO wäre, ich würde erstmal die Beispiele der Lib versuchen zu kompilieren. Das soll ja alles auch auf einem ATmega328P funktionieren, also muss das eigentlich laufen. Danach kann man immer noch daran rumfummeln, wenn man weiß was man tut.
? listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
4
? configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
5
2 struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */
6
2 struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */
7
2 void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
8
2 void * configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any). */
9
? listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
10
};
11
typedef struct xLIST_ITEM ListItem_t;
12
13
typedef struct tskTaskControlBlock
14
{
15
2 volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
16
17
#if ( portUSING_MPU_WRAPPERS == 1 )
18
? xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
19
? BaseType_t xUsingStaticallyAllocatedStack; /* Set to pdTRUE if the stack is a statically allocated array, and pdFALSE if the stack is dynamically allocated. */
20
#endif
21
22
8 ListItem_t xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
23
8 ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
24
? UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
25
2 StackType_t *pxStack; /*< Points to the start of the stack. */
26
char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
Muss ich die I/O Register beim Taskwechsel auch speichern?
Schon das Lesen kann den Zustand des zugehörigen Peripheriegeräts ungewollt verändern. Und das Zurückschreiben gespeicherter Inhalte ist noch schlimmer.
Und das auch noch in unterschiedlichen Tasks? ουαί κι αλίμονό μου!
Das steht in keinem Datenbuch ausdrücklich drin, weil es für jeden Profi absolut selbstverständlich ist.
Aber sicher, man muss nur des sinnerfassenden Lesens mächtig sein. Bei ALLEN IO-Registern steht, ob und wie ein Schreib- oder Lesezugriff eine Reaktion bewirkt.
Ja, wenn man nur wüsste, was eigentlich. Denn aktuell ist das klassische xy-Problem. Du bastelst an Lösungen, die mit deinem Problem gar nichts zu tun haben.
ich habe den Eindruck, dass du deine Fähigkeiten extrem überschätzt. Du willst ein RTOS Betriebssystem neu erfinden, ohne den Prozessor zu kennen. Was du vor hast ist machbar, aber das wird nach meiner Einschätzung einige Monate dauern.
100% sicher ist, dass du damit den Fokus auf die Problemursache verlierst. Du verzettelst dich mit einem komplexen Balkon, der dein Problem nicht löst, sondern höchstwahrscheinlich noch schwieriger begreifbar macht. Man soll ja junge Leute nicht demotivieren, doch es tut mir in der Seele weh, zu sehen, wie du mit Anlauf vor die Wand läufst.
Auf dem kleinen Mikrocontroller wird ein aktive Multitasking so viel RAM und CPU Leistung verschlucken, dass du damit nicht glücklich wirst - falls du es überhaupt schaffst.
Aber: Finde erst mal die Fehlerursache in deinem Programm! Nur wenn man seine eigenen Fehler erkannt und verstanden hat, kann man es danach besser machen.
ich habe den Eindruck, dass du deine Fähigkeiten extrem überschätzt.
Wenn er es bis hierher nicht verstanden hat dann darf man ihm
Beratungsresistenz attestieren.
Leider ist der Thread gestern, am Freitag, entstanden. Was auch
kein gutes Zeichen ist. Allein CAN und Multitasking in Einem
auf dem ATmega328P lässt mich schon ganz schwindelig werden.
Was der Matthias vielleicht noch nicht auf sich zu kommen sieht:
Wenn mehrere Threads auf gemeinsame Resourcen zugreifen (z.B. ein Display oder der CAN Bus), dann muss man irgendwie dafür sorgen, dass das in einer geordneten Reihenfolge passiert (Semaphoren). Das läuft oft auf gepufferte Ein/Ausgabe hinaus, für die er aber nicht genug RAM haben wird, da das ja schon von Registern und Stack der Threads "aufgefressen" wurde.
Aber sicher, man muss nur des sinnerfassenden Lesens mächtig sein. Bei
ALLEN IO-Registern steht, ob und wie ein Schreib- oder Lesezugriff eine
Reaktion bewirkt.
Dann lies mal richtig. Was habe ich denn gesagt und was nicht?
Und worauf bezog sich das?
Die allgemeine Aussage, dass man bei I/O-Registern nicht einfach blind lesen und schreiben darf, da es – im Gegensatz zu "normalen" Speicherregistern – gar keine Speicher, sondern nur Adressen zum Übermitteln von Befehlen und Stati an/von Peripheriegeräten sind, die steht eben nicht ausdrücklich drin.
Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.
Sowas ähnliches habe ich auch im Einsatz. Auf CAN und UART fahre ich das gleiche Stringprotokoll. Der CAN-Interrupt teilt die Nachrichten in 8-Byte Pakete auf bzw. liest sie ein.
RS485 und CAN lesen einfach in getrennte Puffer. Und sobald das Endezeichen erkannt wird, geht beides in den gemeinsamen Parser, der es dann ausführt und die Antwort in den CAN- bzw. UART-Puffer bastelt.
Nirgends kann was hängen bleiben und Multitasking ist erst recht völlig unnötig.
Sämtliche Parameter (ADC, I2C usw.) werden im Hintergrund permanent eingelesen. Der Parser muß also nirgends warten, sondern schickt gleich die Antworten.
Als Schmankerl gibt es noch eine Autosend-Funktion. Der Master schickt dazu den Parameternamen und das gewünschte Intervall. Dann muß er nicht jedes mal erneut anfragen, sondern bekommt zyklisch alles geschickt.
Was Deine Registerrettungsorgie mit der Fragestellung zu tun hat, ist mir jedoch ein völliges Rätsel.
Das ist nur unnütze Verschwendung von RAM, Code und CPU-Zeit.
Ohne Multitasking wird es arg kompliziert, wenn da irgendwas hängen
bleibt.
Multitasking hilft aber nicht gegen Programmfehler. Im Gegenteil, es macht die Funktionen nur unnötig kompliziert und damit Fehler wahrscheinlicher.
Wenn man die Abläufe sauber strukturiert, kann auch nichts "hängenbleiben".
Ich hab mir jetzt Microchip Studio runtergeladen und schon paar Fehler
gefunden.
Das stimmt. Besonders in Simulatoren kann man in Microchip Studio viele Fehler finden.
Ich sehe dein Problem aber woanders: du willst Inline Assembler benutzen, ohne AVR einigermaßen kennenzulernen.
An deiner Stelle würde ich zuerst ein paar Projekte mit C und mit Assembler machen, dann etwas mit Inline Assembler Schritt zu Schritt, und erst danach mit RTOS experimentieren. Nur so wirst du verstehen, was du machst.
Frage, was passiert mit den Registern und Stack im Interrupt?
Beim AVR8? So gut wie nix. Der PC wird auf den Stack gesichert und das I-Flag in SREG gelöscht. Für alles andere ist man selbst (oder der Compiler) verantwortlich.
Kann ich da im Interrupt einfach einen Task starten oder Taskwechsel
machen?
Üblicherweise nicht. Üblicherweise ist so ein Multitasking-OS sinnvollerweise so konstruiert, dass die Devicetreiber (und der Task-Scheduler) das einzige sind, was überhaupt Interrupthandler implementiert.
Und die Devicetreiber ihrerseits füttern oder entleeren üblicherweise nur Queues im RAM. Maximal können sie noch dafür sorgen, dass der Task, der auf ein entsprechendes Ereignis wartet, in der Prioritätsliste nach oben wandert.
Fazit: ein Riesenhaufen Verwaltungs-Overhead, den niemand benötigt, der wirklich programmieren kann...
Klar, man kann auch mit einem RTOS was zum Laufen bringen, aber das Ergebnis wird massiv suboptimal sein. Nunja: solange die Rechenzeit-Resourcen dafür reichen, dass es halt den Anforderungen der Anwendung genügt, ist das egal. Aber wehe, es kommt was dazu...
Dann ist das Bein genauso dicke, als hätte man den Kram "klassisch" implementiert, also ohne RTOS. Der Unterschied ist halt nur: das wird bei einem RTOS-Ansatz bei gegebener Hardware viel früher passieren. Dafür sorgt eben der Overhead des RTOS...
Frage, was passiert mit den Registern und Stack im Interrupt?
Beim AVR8? So gut wie nix. Der PC wird auf den Stack gesichert und das
I-Flag in SREG gelöscht. Für alles andere ist man selbst (oder der
Compiler) verantwortlich.
Bei mir hat der Compiler zumindest einen Teil der Register auf dem Stack gesichert und vor reti wieder geladen.
ISR() vollzieht also sowas wie einen Taskwechsel, wenn es nicht mit attribute((naked)) ist.
Fazit: ein Riesenhaufen Verwaltungs-Overhead, den niemand benötigt, der
wirklich programmieren kann...
Klar, man kann auch mit einem RTOS was zum Laufen bringen, aber das
Ergebnis wird massiv suboptimal sein. Nunja: solange die
Rechenzeit-Resourcen dafür reichen, dass es halt den Anforderungen der
Anwendung genügt, ist das egal. Aber wehe, es kommt was dazu...
Dann ist das Bein genauso dicke, als hätte man den Kram "klassisch"
implementiert, also ohne RTOS. Der Unterschied ist halt nur: das wird
bei einem RTOS-Ansatz bei gegebener Hardware viel früher passieren.
Dafür sorgt eben der Overhead des RTOS...
Ja, mal schauen. Wenn es mir am Ende nicht gefällt, kann ich es immer noch mit einem while(1){switch} neu machen.
ISR(TIMER2_COMPA_vect) ist per default nicht naked...
Und gut so. Naked brauchst du selten. Z.B. dort wo SREG in ISR nicht geändert wird. Oder muß du per Hand SREG und alle benutzten Register in Stack legen. Aber Compiler selbst macht das noch besser. Nur vergiß nicht, Optimieren auf -Os zu stellen. Dummerweise macht Microchip Studio für neue Projekte -Og.
Verdammte kleine Mistdinger, ist doch alles komplizierter als gedacht.
Aber nur, wenn man es sich absichtlich kompliziert machen will.
Die Mehrheit läßt einfach den Compiler sich um alles kümmern und pfuscht ihm nicht mit Assembler ins Handwerk.
Was stört Dich denn an der Mainloop mit Interrupts Methode?
Hast Du überhaupt schonmal irgend was programmiert oder ist das Dein Einsteigerprojekt?
Ein RTOS zu verwenden macht übrigens auf anderen Controllern deutlich mehr Sinn, wie z.B. Cortex-M. Die sind im Gegensatz zu den AVR extra dafür konzipiert und können den Kontextwechsel fast automatisch und sehr effizient. Außerdem haben die Support für Atomics, Speicherschutz (MPU) und Privilegierung/Separierung von OS und Anwendung, Interrupt-Prioritäten usw. Rein zufällig gibt es dafür auch schon fertige RTOS wie eben FreeRTOS.
Nur vergiß
nicht, Optimieren auf -Os zu stellen. Dummerweise macht Microchip Studio
für neue Projekte -Og.
Für seinen Fall wäre -Og besser:
-Os: Diese Option optimiert den Code für die Größe des resultierenden ausführbaren Programms. Der Compiler versucht, den Code so zu optimieren, dass er weniger Speicherplatz benötigt, auch wenn dies möglicherweise auf Kosten der Ausführungsgeschwindigkeit geht. Das ist besonders nützlich für eingebettete Systeme oder Programme, bei denen die Größe des Binärdatei eine Rolle spielt.
-Og: Diese Option steht für "Optimize for Debugging". Im Gegensatz zu anderen Optimierungsstufen versucht "-Og" nicht, den Code stark zu optimieren. Stattdessen optimiert es den Code auf eine Weise, die das Debuggen erleichtert. Das bedeutet, dass der generierte Code lesbarer bleibt und das Debuggen einfacher ist, da Variablenwerte leichter nachvollziehbar sind. Diese Option ist besonders nützlich während der Entwicklungsphase, wenn die Hauptpriorität das Debuggen und die Fehlersuche sind.
Der Compiler versucht, den Code so zu
optimieren, dass er weniger Speicherplatz benötigt, auch wenn dies
möglicherweise auf Kosten der Ausführungsgeschwindigkeit geht.
Meine Erfahrung: mit -Os gewinnt man beides, auch Ausführungsgeschwindigkeit. Noch interessanter: manche Sachen, die mit -Os gut funktionieren, werden mit -Og Fehler bringen. Ein Beispiel:
1
ISR(TIMER1_COMPA_vect,ISR_NAKED){/* Timer/Counter1 Compare Match A */
2
PORTB|=1<<2;
3
reti();
4
}
Mit -Os bekommen wir:
1
SBI 0x05,2
2
RETI
Das wird funktionieren.
Mit -Og bekommen wir:
1
IN R24,0x05
2
ORI R24,0x04
3
OUT 0x05,R24
4
RETI
Scheinbar wird das auch funktionieren, nur langsamer. In Wirklichkeit aber werden hier SREG und R24 in ISR geändert, das führt zu groben Programmfehler.
KA, es gibt gefühlte 20 Tausend Arduino Libs.
Sicherlich nutzen einige davon die ProtoThreads, davon musst du ausgehen.
Und seit die Coroutinen in C++ Einzug gehalten haben, wird das Konzept wohl in Zukunft häufiger zu finden sein.
Busy-Wait, naja, ich glaub das kommt man noch so gerade selber drauf. Die lock Funktion sollte den Thread schlafen legen und sofort zu anderen Threads wechseln. Inkl. Priority Boosting des aktuell den Mutex besitzenden Threads. Und rekursiv funktioniert es auch nicht.
Du müsstest halt genau dieses API implementieren damit die pthread Funktionen was aufrufen können. Aber warum POSIX Threads und nicht Standard C bzw. C++ threading?
Ein Zustandsautomat definiert das einfach auf nichts und der wo es
braucht, implementiert das je nach eigenen Vorstellungen.
Du meinst wohl ein Makro. Ganz so einfach ist es in der Praxis nicht. Multi-Threading ist nicht nur ein Balkon den man wahlweise weg lassen kann. Das ganze Programm muss strukturell darauf ausgelegt sein und das bekommt man nicht zum Nulltarif.
Das wäre dann doch der ideale Zeitpunkt, das ganze RTOS selber bauen Gedöns grundsätzlich fallen zu lassen. Und vor allem, wenn man keinerlei Ahnung davon hat.
Nur wegen der 2 Schnittstellen muß man noch lange nicht mit Kanonen auf Spatzen schießen.
Soweit ich weiß werden Coroutinen in avr-g++ nicht unterstützt, gleiches gilt für Atomics.
In der AVR LibC gibt es einige Funktionen, die nicht reentrant sind.
Und die gezeigten Inline Asm Schnipsel funktionieren vielleicht mit viel Gluck, stellen aber keinen validen Code dar (inkorrekter Code darf funktionieren, muss aber nicht).
Das wäre dann doch der ideale Zeitpunkt, das ganze RTOS selber bauen
Gedöns grundsätzlich fallen zu lassen. Und vor allem, wenn man keinerlei
Ahnung davon hat.
Ganz genau. Wenn ein RTOS irgendeinen Sinn ergeben soll, dann doch allenfalls, wenn man es nicht erst noch selber basteln muss.
Wenn man das nämlich kann, hat man auch keinerlei Probleme damit, eine Anwendung ganz klassisch ohne RTOS umzusetzen.
Wenn man das nämlich kann, hat man auch keinerlei Probleme damit, eine
Anwendung ganz klassisch ohne RTOS umzusetzen.
Oft ist man auf externe proprietäre Bibliotheken/Frameworks angewiesen, welche synchron implementiert sind. Wenn man dann noch andere Dinge parallel laufen lassen möchte, braucht man ein RTOS. Das allerdings kompatibel zu solchen Bibliotheken zu machen könnte interessant werden.
Oft ist man auf externe proprietäre Bibliotheken/Frameworks angewiesen,
welche synchron implementiert sind.
Ist mir noch nie passiert. Hast du Beispiele?
Wenn man dann noch andere Dinge
parallel laufen lassen möchte, braucht man ein RTOS.
Selbst dann nicht wirklich. Kommt allerdings auch ein wenig darauf an, was genau da parallel laufen muss. Wenn das dann eine zweiter synchroner zusammengeklauter Scheiß ist, dann könnte es tatsächlich eng werden...
Also: weniger klauen, mehr selber programmieren und gut isses.
OpenSource: Die STM32WL55 RF und LoRa Middleware, der ATWILC-Treiber, FatFs, die I²C-Libraries für die alten STM32, überhaupt alle möglichen Libraries für (I²C-)Sensoren und Peripherie-ICs
Es gibt bestimmt noch viele mehr für exotische Protokolle z.B. in der Industrie. Die APIs der ESP32 sind größtenteils synchron, aber dort benutzt man ja sowieso FreeRTOS.
Die OpenSource-Libraries kann man prinzipiell umbauen, aber der Aufwand ist oft nicht gerechtfertigt. Wenn man nur ein Framework dieser Art hat kann man sich herauslavieren indem man den Rest asynchron macht, aber sobald es mehr als eins ist braucht man ein RTOS. Ich habe das Gefühl, dass die ganze Embedded-Industrie das Komponentenparadigma nicht verstanden hat - die Annahme ist immer, man nutzt exakt 1 Framework an welchem man das ganze Projekt ausrichtet und sonst nichts.
Mein (AVR) Arduino beschwert sich zumindest nicht über ein1#include
<coroutine>
Jetzt musst du nur noch die AVR-gcc toolchain mit multithreading enabled bauen, und schon wird es auch funktionieren. Die dafür benötigten „Kleinigkeiten“ werden dich ja nicht groß überfordern…
Ich seh jetzt nicht wie man Threads vernünftig unterstützen kann ohne entsprechenden OS Support. RTEMS+Newlib Support für AVR wurden vor X Jahren fallen gelassen. Und pthreads gibt's auch keine.
Meine Erfahrung ist, es funktioniert am zuverlässigsten, wenn man dem Compiler nicht ins Handwerk pfuscht. Die Compilerbauer verstehen schon ihr Handwerk.
Ich hab mal in einem früheren Projekt naked Interrupts mit Assembler benutzt, um dem AVR eine 2. Priorität beizubringen. Rückblickend würde ich das aber nicht als Masterpiece ansehen.
Meine Erfahrung ist, es funktioniert am zuverlässigsten, wenn man dem
Compiler nicht ins Handwerk pfuscht. Die Compilerbauer verstehen schon
ihr Handwerk.
Das Problem ist, man programmiert halt und rechnet den Speicherbedarf aus und dann wächst der Stack doch plötzlich da rein, wo er nicht hin soll und das Teil stürzt unkontrolliert ab.
Wenn man jetzt bissl Luft lässt, so dass man nicht vor jedem Stackzugriff prüfen muss, könnte man optional schon Rechenzeit gegen Sicherheit tauschen und bei einem Überlauf den laufenden Thread beenden.
Klar kann man auch den Code manuell vor dem Compilerdurchgang mit Stacküberlauftests durchziehen, aber...
Klar kann man auch den Code manuell vor dem Compilerdurchgang mit
Stacküberlauftests durchziehen, aber...
Ich habe in meinen Programmen 2 kleine Prüffunktionen implementiert, die man per Kommando aufrufen kann. Einmal wird der freie Bereich zwischen Daten und Stackpointer mit 0x77 gefüllt und getestet, wieviel davon seit dem letzten Aufruf übrig ist.
Die andere Funktion zählt die maximalen Timerticks (1ms) zwischen 2 Durchgängen der Mainloop. Beim ersten Aufruf kriegt man die Dauer aller Initialisierungen angezeigt.
Damit läßt sich bequem die maximale Auslastung während der Laufzeit ermitteln.
Weiterhin wird noch der letzte Resetgrund ausgegeben. Ist dieser seit dem letzen Start der Applikation 0x00, dann ab zurück zum Debuggen. Denn dann ist ja ein wilder Pointer in den Resetvektor gelaufen, d.h. dieses Programm darf nicht ausgeliefert werden.
Ich habe in meinen Programmen 2 kleine Prüffunktionen implementiert, die
man per Kommando aufrufen kann. Einmal wird der freie Bereich zwischen
Daten und Stackpointer mit 0x77 gefüllt und getestet, wieviel davon seit
dem letzten Aufruf übrig ist.
Die andere Funktion zählt die maximalen Timerticks (1ms) zwischen 2
Durchgängen der Mainloop. Beim ersten Aufruf kriegt man die Dauer aller
Initialisierungen angezeigt.
Damit läßt sich bequem die maximale Auslastung während der Laufzeit
ermitteln.
und wie schaffst du es alle anfallenden Bedingungen zu testen?
Wie erkennst du zerpflückte nicht zusammenhängende Speicherbereiche?
Ich denke an PET2001 da gab es die garbadge collection, der Müll mußte ab und an rausgetragen werden.
Ich denke an AtariST TOS 1.0 wo nach 128 malloc/free Aufrufe gebombt wurde, also Absturz, was mit TOS 1.4 nur auf 1024 malloc/free Aufrufe erweitert wurde aber das Problem nur verschob.
Ich dachte auch mal man könnte auf kleinere AVR sowas machen, aber der Code wurde immer aufgeblähter und passte dann nicht mehr ins flash.
Meine Erfahrungen, bekannte viel genutzte Variablen nicht dynamisch zuzuweisen sondern schon vorher zu reservieren, verringert zwar den freien SRAM aber es kommen zur Laufzeit keine Überraschungen.
Speicher ist wie Hubraum, durch nichts zu ersetzen. Die kleinen Motoren mit Turbo aufzublasen schaffen auch mehr Probleme als sie lösen, Golf mit 1,4L und Turbo fällt mir da ein oder die Ford EcoBoost mit in Öl laufenden Zahnriemen.
Klar kann man auch den Code manuell vor dem Compilerdurchgang mit
Stacküberlauftests durchziehen, aber...
Ich habe in meinen Programmen 2 kleine Prüffunktionen implementiert, die
man per Kommando aufrufen kann. Einmal wird der freie Bereich zwischen
Daten und Stackpointer mit 0x77 gefüllt und getestet, wieviel davon seit
dem letzten Aufruf übrig ist.
Die andere Funktion zählt die maximalen Timerticks (1ms) zwischen 2
Durchgängen der Mainloop. Beim ersten Aufruf kriegt man die Dauer aller
Initialisierungen angezeigt.
Damit läßt sich bequem die maximale Auslastung während der Laufzeit
ermitteln.
Weiterhin wird noch der letzte Resetgrund ausgegeben. Ist dieser seit
dem letzen Start der Applikation 0x00, dann ab zurück zum Debuggen. Denn
dann ist ja ein wilder Pointer in den Resetvektor gelaufen, d.h. dieses
Programm darf nicht ausgeliefert werden.
Hm, eine dritte ISR die den SP überwacht, das eine sehr gute Idee!!
Baue das heute Abend ein, nachdem ich die ganzen Fehler behoben habe, die ich gestern Abend nach zwei Bier reingeschusselt hab...
Aus meine Sicht eher zu jung. Ein mittelprächtig anspruchsvolles Programm mit aufwendigen Mitteln lösen zu wollen, spricht eher für mangelnde Weitsicht. Ich kann nur Falk beipflichten:
Falk B. schrieb im Beitrag #7663101:
Aber für bissel CAN und Solaranlage scheint das hier
eine verdammt aufgeblähte Lösung zu sein.
Es wäre aus meiner Sicht angebracht, zwei Schritte zurückzutreten, das Projekt neu aufzusetzen und sich zunächst mal um die einfacheren Varianten des Multitasking zu kümmern.
realisiert man am sinnvollsten und minimal Overhead produzierend mit einem regelmäßigen Timerinterrupt, der ganz einfach alle regelmäßig zu erledigenden Sachen aufruft.
Oh wie cool, der hat ja noch mehr Registersätze! Ich dachte, der Z80 sei
der einzige Prozesser dieser Art.
Heute wäre die Werbung für den TMS9900 "Bis zu 2047 Registersätze!"
Wirklich schade, dass diese Architektur aus der Mode gekommen ist. Mit 1MByte On Chip RAM und 0 Wait States würde das gut funktionieren.
Die Register die beim Taskwechsel gerettet werden müssen sind ja nur das eine. Man gönnt jedem Task ja seinen eigenen Stack. Wenn man da sparsam ist dann kann es in langen Debug Sessions enden, oder man ist großzügig, muss dann aber auch genug RAM haben.
Genug Gründe um für preemptives MT Cortex-M einzusetzen.
Hm, eine dritte ISR die den SP überwacht, das eine sehr gute Idee!!
Dazwischen kann aber auch sehr viel passieren...
Das testweise Markieren des Zwischenraums Daten<>Stack a'la Peter D. ist sicher die bessere Idee. Diese Markierung performance- gesittet d.h. stückweise zu kontrollieren wäre für besagte periodische ISR m.M. eine sinnvollere Aufgabe.
Im allgemeinen aber sollten fehlgeleitete SRAM Zugriffe und Stackfehler- und damit der nötige Einsatz von Kontroll- Instrumenten die absolute Ausnahme darstellen. Kann gut sein daß man da mit Assembler besser am Puls der Hardware hört und dran ist :)
Die andere Funktion zählt die maximalen Timerticks (1ms) zwischen 2
Durchgängen der Mainloop.
Ich hab dafür (so verfügbar) einen Hardware TC-Counter mit vollem Speed = maximaler Zeitauflösung laufen. Der kann dann nicht nur zu verschiedenen Zeitpunkten in der Main abgefragt werden sondern auch in Interrupts, um die Zeiten der Abarbeitung derselben zu kontrollieren.
Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.
Kann mir bitte einer sagen, was da nicht stimmt?
Du hast die Netiquette nicht beachtet, längere Quelltexte gehören in
den Anhang.
Ich habe schon die
ganze Nacht gesucht. Leider sind da in dem Quelltext von dem TCB_t und
ListItem_t so viele #ifdef dass ich nicht weiß, wie ich aus einem
StackType_t * ein TCB_t bekomme.
Ich auch nicht. Aber für bissel CAN und Solaranlage scheint das hier
eine verdammt aufgeblähte Lösung zu sein.
Hab dem Teil noch paar Eventhandler für Arme spendiert...
Hätte gerne noch sowas wie eine Scriptsprache, oder einen Interpreter
für bytecode, damit man Fernupdates machen kann.
Warum brauchst du das für Fernupdates?
Wenn ich die Steuerung von der Solaranlage und später mal Heizung fest einprogrammiere, sehe ich mich schon dauernd mit dem Laptop auf einem Hocker im Keller sitzen und das Teil umprogrammieren.
Noch dazu ist das Script kleiner, da hebt sich der zusätzliche Speicherverbrauch schnell auf...
Wenn ich die Steuerung von der Solaranlage und später mal Heizung fest
einprogrammiere, sehe ich mich schon dauernd mit dem Laptop auf einem
Hocker im Keller sitzen und das Teil umprogrammieren.
Das erklärt nicht, warum es eine Skriptsprache für das Update braucht.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook! Ook.