poniedziałek, 30 stycznia 2023

Colibri iMX6 - Watchdog

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:

  1. root@colibri-imx6:~# ls -la /dev/watchdog*
  2. crw-------    1 root     root       10, 130 Apr  1  2019 /dev/watchdog
  3. 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:

  1. "/dev/watchdog"

Parametry dla watchdoga zostały opisane w pliku system.conf

  1. nano /etc/systemd/system.conf
  2.  
  3. #RuntimeWatchdogSec=0
  4. #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:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include "watchdog.h"
  5.  
  6. int main(void) {
  7.     int ret = 0;
  8.     ret = Watchdog_init("/dev/watchdog");
  9.  
  10.     if(ret < 0) {
  11.         fprintf(stderr, "Init watchdog error %s\n", strerror(errno));
  12.     }
  13.  
  14.     while(1)
  15.     {
  16.         ret = Watchdog_hwfeed();
  17.         if(ret < 0) {
  18.             return ret;
  19.         }
  20.         sleep(1);
  21.     }
  22.     return EXIT_SUCCESS;
  23. }

Na samym początku procedura uruchomienia watchdoga:

  1. int Watchdog_init(const char *pcDevice)
  2. {
  3.     int ret = 0;
  4.     ret = Watchdog_open(pcDevice);
  5.     if(ret < 0){
  6.         return ret;
  7.     }
  8.     ret = Watchdog_hwfeed();
  9.     return ret;
  10. }

Otwieramy podany plik, jeśli operacja przeszła poprawnie to aktualizujemy licznik.

Otwarcie pliku:

  1. int Watchdog_open(const char * watchdog_device)
  2. {
  3.     int ret = -1;
  4.     if (api_watchdog_fd >= 0){
  5.         fprintf(stderr, "Watchdog already opened\n");
  6.         return ret;
  7.     }
  8.     api_watchdog_fd = open(watchdog_device, O_RDWR);
  9.     if (api_watchdog_fd < 0){
  10.         fprintf(stderr, "Could not open %s: %s\n", watchdog_device, strerror(errno));
  11.         return api_watchdog_fd;
  12.     }
  13.     return api_watchdog_fd;
  14. }

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:

  1. int Watchdog_hwfeed(void)
  2. {
  3.     int ret = -1;
  4.     if (api_watchdog_fd < 0){
  5.         fprintf(stderr, "Watchdog must be opened first!\n");
  6.         return ret;
  7.     }
  8.     ret = ioctl(api_watchdog_fd, WDIOC_KEEPALIVE, NULL);
  9.     if (ret < 0){
  10.         fprintf(stderr, "Could not pat watchdog: %s\n", strerror(errno));
  11.     }
  12.     return ret;
  13. }

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.  


Dokumentacja: