W tym poście chciałbym opisać sposób uruchomienia Watchdoga w układach Colibri iMX6.
Watchdog może być użyty do kilku celów. Zapewnienie resetu, spowodowanego zawieszeniem sprzętu. W tym celu należy uruchomić odpowiednie opcje w pliku system.conf (opis poniżej). Drugi przypadek dotyczy zawieszenie aplikacji, podobnie jak poprzednio należy wprowadzić odpowiednie definicje. Ostatni przypadek dotyczy kilku nieudanych prób resetu aplikacji.
Następujące wywołanie komendy z konsoli wyświetli dostępne interfejsy watchdog:
- root@colibri-imx6:~# ls -la /dev/watchdog*
- crw------- 1 root root 10, 130 Apr 1 2019 /dev/watchdog
- crw------- 1 root root 248, 0 Apr 1 2019 /dev/watchdog0
Oba interfejsy wskazują na to samo miejsce.
W celu obsługi watchdoga należy otworzyć plik:
- "/dev/watchdog"
Parametry dla watchdoga zostały opisane w pliku system.conf
- nano /etc/systemd/system.conf
- #RuntimeWatchdogSec=0
- #ShutdownWatchdogSec=10min
Domyślnie timeout dla watchdoga jest ustawiony na 60 sekund.
Ogólnie obsługa watchdoga składa się z dwóch elementów. Na samym początku musimy otworzyć odpowiedni plik. Kolejnym i ostatnim elementem jest przeładowywanie licznika.
Należy pamiętać, że watchdoga można obsługiwać tylko z jednego miejsca. Jeśli zdefiniujemy proces systemowy, to nie będziemy wykonywać dostępu do niego z osobnego programu.
Program główny może wyglądać w następujący sposób:
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include "watchdog.h"
- int main(void) {
- int ret = 0;
- ret = Watchdog_init("/dev/watchdog");
- if(ret < 0) {
- fprintf(stderr, "Init watchdog error %s\n", strerror(errno));
- }
- while(1)
- {
- ret = Watchdog_hwfeed();
- if(ret < 0) {
- return ret;
- }
- sleep(1);
- }
- return EXIT_SUCCESS;
- }
Na samym początku procedura uruchomienia watchdoga:
- int Watchdog_init(const char *pcDevice)
- {
- int ret = 0;
- ret = Watchdog_open(pcDevice);
- if(ret < 0){
- return ret;
- }
- ret = Watchdog_hwfeed();
- return ret;
- }
Otwieramy podany plik, jeśli operacja przeszła poprawnie to aktualizujemy licznik.
Otwarcie pliku:
- int Watchdog_open(const char * watchdog_device)
- {
- int ret = -1;
- if (api_watchdog_fd >= 0){
- fprintf(stderr, "Watchdog already opened\n");
- return ret;
- }
- api_watchdog_fd = open(watchdog_device, O_RDWR);
- if (api_watchdog_fd < 0){
- fprintf(stderr, "Could not open %s: %s\n", watchdog_device, strerror(errno));
- return api_watchdog_fd;
- }
- return api_watchdog_fd;
- }
Na samym początku sprawdzany jest deskryptor z informacją czy plik jest już otwarty (czyli czy wartość została już przypisana do zmiennej). Jeśli tak to nie próbujemy robić tego ponownie. Po jego otwarciu zwracamy deskryptor.
Aktualizacja licznika:
- int Watchdog_hwfeed(void)
- {
- int ret = -1;
- if (api_watchdog_fd < 0){
- fprintf(stderr, "Watchdog must be opened first!\n");
- return ret;
- }
- ret = ioctl(api_watchdog_fd, WDIOC_KEEPALIVE, NULL);
- if (ret < 0){
- fprintf(stderr, "Could not pat watchdog: %s\n", strerror(errno));
- }
- return ret;
- }
Tutaj jak plik otwarty to wywołujemy funkcję ioctl. Jako argumenty podawany jest deskryptor oraz flaga wykonująca aktualizację licznika. Jeśli operacja przeszła pomyślnie następuje wyjście z funkcji.