Watchdogs - это замечательно, но и боль в тылу, когда ваша программа или система не легко вписываются в нее.Лучше всего работать, когда у вас есть код, который выглядит (как правило) как:
Watchdog_init();
hardware_init();
subsystem1_init();
subsystem2_init();
subsystem3_init();
...
subsystemN_init();
forever {
Watchdog_tickle();
subsystem1_work();
subsystem2_work();
subsystem3_work();
...
subsystemN_work();
}
Очень часто вы можете разработать свою программу таким образом, чтобы это работало, и, как правило, это очень надежно (но не полностью).
Но в таких случаях, как ваш, это не так хорошо работает.Вы заканчиваете тем, что должны спроектировать и создать (или возможно использовать библиотеку) структуру, которая имеет различные условия, которые должны быть выполнены, которые контролируют, если / когда сторожевой таймер получает петтинг.Это может быть очень сложно, хотя.Сложность этого кода сама по себе может вносить свои ошибки.Вы могли бы очень хорошо написать идеальное приложение, за исключением сторожевого фреймворка, и ваш проект может много перезагружаться, или весь ваш код может быть плохим и просто постоянно ласкать сторожевой таймер, заставляя его никогда не сбрасываться.
Один хорошийЧтобы изменить приведенный выше код для обработки более сложных ситуаций, можно изменить функции subsystemX_work, чтобы не отставать от состояния.Это можно сделать с помощью статических переменных в функциях или с помощью указателей функций, а не функций, и изменить фактическую функцию, которая выполняется, чтобы отразить текущее состояние этой подсистемы.Каждая подсистема становится конечным автоматом.
Еще один способ обойти длительные преднамеренные ожидания с быстрым сторожевым сторожевым таймером - это разбить долгосрочную функцию на более короткие части.Вместо:
slow_device_init();
Watchdog_tickle();
Вы можете сделать:
slow_device_init_begin();
Watchdog_tickle();
slow_device_init_finish();
Watchdog_tickle();
А затем расширить это, чтобы растянуть сторожевой таймер, выполнив:
slow_device_init_begin();
for ( i = SLOW_DEV_TRIES; i ; i--) {
Watchdog_tickle();
if (slow_device_init_done()) {
break;
}
}
Watchdog_tickle();
Даже если это возможностановиться все сложнее и сложнее.Часто вам в конечном итоге приходится создавать сторожевого делегата, который просто проверяет условия, которые должны быть выполнены, и делает или не ласкает сторожевого таймера, основываясь на этих условиях.Это начинает становиться очень сложным.Это может быть реализовано путем создания объекта для каждой из ваших подсистем, который имеет некоторый метод / функцию для вызова, чтобы проверить состояние подсистемы.Методы работоспособности могут быть очень сложными и даже могут меняться по мере изменения состояния этой подсистемы, хотя это должно быть как можно более простым, чтобы как можно проще было проверить правильность кода, а также потому, что меняется то, какРабота подсистемы потребует изменений в том, как вы измеряете работоспособность.
Если вы можете гарантировать, что какой-то код выполняется через регулярные интервалы, тогда у вас может быть просто целое число для каждой подсистемы, которое действует как локальный сторожевой таймер подсистемы.Некоторый код (возможно, в обработчике прерывания по таймеру, но не обязательно) будет уменьшать и проверять переменную каждой подсистемы.Если она достигает 0 для любой подсистемы, то сторожевой таймер не срабатывает.
Watchdog_periodic() {
for_each subsustem in subsystem_list { // not C, but you get the idea
if ( 0 > --(subsystem->count_down) ) {
// Do something that causes a reset. This could be returning and not petting
// the hardware watchdog, doing a while(1);, or something else
}
}
Watchdog_tickle();
}
Тогда каждая подсистема может изменять свой собственный count_down для различного количества времени, устанавливая ее count_down в положительное значение.
Вы также должны заметить, что на самом деле это просто программный сторожевой таймер, хотя он может использовать аппаратный сторожевой таймер для фактического сброса.
Следует также отметить, что чем сложнее сторожевая платформа, тем больше возможностейесть ошибки в нем, а также возможность ошибок в другом коде, чтобы заставить его работать неправильно.Например, ошибка указателя, такая как:
int x;
fscanf(input, "%i", x); // Passed uninitialized x rather than address of x
, может привести к установке значения count_down в подсистеме, что может привести к тому, что сторожевой таймер не будет кусаться, когда это необходимо.