Daniel A. schrieb:
Vielleicht kannst du statt einer Modul ID einfach das static keyword
nehmen?
Ich habe nicht geschrieben, wofür ich das brauche… Das hole ich jetzt nach:
Mein Programmpaket enthält einen Header namens config.h, der in alle Module an erster Stelle nach den Library-Includes includet wird. Dort stehen die grundlegenden Generierungsparameter drin und unter anderem auch die Modul-IDs für jeden .c-File und die Fehlernummern, die in dem jeweiligen Modul vorkommen. (Die ModulID und Fehlernummer kann bei fatalen Fehlern mit einer LED signalisiert werden und anhand der Nummern findet man mittels config.h sehr schnell die Stelle, an der es gerumst hat.)
In jedem .c-Modul steht nach den includes ein
#define MODULE_ID MODULE_MAIN_C
oder wie der Modul auch immer heißt. (In config.h ist MODULE_MAIN_C als Zahlwert definiert.)
So weit das Vorgeplänkel, das den Trick mit dem cpp lohnend macht. Nun zum aktuellen Problem: ich will den Watchdog so integrieren, dass er dem Programm mit einem Reset wieder auf die Beine hilft, wenn es sich irgenwo verlaufen hat.
Dummerweise hatte ich in etlichen Modulen und teilweise ganz tief in den Hardware-Dingen wdt_rest() Aufrufe eingebaut. Als ich nun die wdt_reset an kritischen Stellen im Programm testweise lahmlegte, hätte der WD einen Reset machen sollen – hat er aber nicht, weil eben irgendwo noch andere wdt_reset-Aufrufe waren…
Was tun?
Ich habe in die config.h folgendes Fragment eingefügt:
1 |
#ifndef ALLOW_WDT_ACCESS
|
2 |
#undef wdt_reset
|
3 |
void __wdt_reset(uint8_t moduleID, uint16_t line);
|
4 |
|
5 |
#define WDT_CAT(x, y) x, y
|
6 |
#define WDT_CAT2(x, y) WDT_CAT(x, y)
|
7 |
|
8 |
#define wdt_reset() __wdt_reset(WDT_CAT2(MODULE_ID, __LINE__))
|
9 |
#endif // ALLOW_WDT_ACCESS
|
Nur in watchdog.c ist ALLOW_WDT_ACCESS definiert – damit kann nur der ein echtes wdt_reset ausführen.
Alle andern Module expandieren statt dem üblichen wdt_reset aus avr/wdt.h zu
1 |
__wdt_reset(MODULE_ID, __LINE__)
|
Die Funktion, die statt des Macros aufgerufen wird sieht so aus:
1 |
void __wdt_reset(uint8_t moduleID, uint16_t line) {
|
2 |
uart_puts_P(PSTR("wdt_reset: "));
|
3 |
uintOut(moduleID);
|
4 |
uart_putchar(',');
|
5 |
uintOut(line);
|
6 |
nl();
|
7 |
|
8 |
wdt_reset();
|
9 |
}
|
Weil sie in watchdog.c liegt, wird dort wdt_reset aus avr/wdt.h ausgeführt.
Damit ist mit geringsten Eingriffen eine Trace-Funktion für wdt_reset implementiert, die sich natürlich mit noch weniger Handgriffen wieder deaktivieren lässt…