用香橙派跑图片爬虫确实很方便,但有时候香橙派会自己死机,也不知道为什么。查了下用户手册发现香橙派Zero2的其实是有一个硬件看门狗的,可以在系统挂掉以后自动重启芯片。

使用看门狗的大概的流程是打开一个叫/dev/watchdog的设备文件,然后使用ioctl函数配置超时时间和手动喂狗。

官方只提供了一个c语言示例程序,所以我打算用python语言来做这个看门狗,但过程不是很顺利。python里需要用到fcntl包下的ioctl方法,这个方法需要传入两个uint类型(32位)的参数。但我的数据因为第32位是1,占用了符号位,python自动给我换成了取值范围更大的类型中去了,导致死活就是传不进去fcntl.ioctl方法,一直提示Python Overflow error: int too large to convert to C long

我试过很多种方法来绕过去,比如直接and 1 << 31,或者通过数字计算来添加第32位为1,这些方法都不行,随后便放弃了python,还是改用c写。

具体的看门狗程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/time.h>
#include <unistd.h>
#include <time.h>
#include <getopt.h>
#include <sys/signal.h>
#include <termios.h>

#define WATCHDOG_IOCTL_BASE 'W'
#define WDIOC_GETSUPPORT _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info)
#define WDIOC_SETTIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
#define WDIOC_GETTIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 7, int) //27
#define WDIOS_DISABLECARD 0x0001       
#define WDIOS_ENABLECARD 0x0002
#define WDIOC_SETOPTIONS _IOR(WATCHDOG_IOCTL_BASE, 4, int)
#define WDIOC_KEEPALIVE _IOR(WATCHDOG_IOCTL_BASE, 5, int)

int running = 1;

void ctl(int fd, unsigned int cmd, unsigned long arg)
{
    int result = ioctl(fd, cmd, &arg);

    if (result < 0)
        printf("ioctl(%d, %ld) fails: %d\n", cmd, arg, result);
}

void signal_handler(int signal)
{
    printf("signal %d\n", signal);
    running = 0;
}

int main(int argc,char **argv)
{
    setbuf(stdout, 0);

    int fd = open("/dev/watchdog", O_RDWR);

    if(fd < 0)
    {
        printf("fail to open watchdog\n");
        return -1;
    }

    // listening linux signals
    signal(SIGINT, signal_handler);

    // enable the watchdog
    ctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD);

    // set a new timeout
    ctl(fd, WDIOC_SETTIMEOUT, 10);

    printf("watchdog is enabled\n");

    // feed dog
    while (running)
    {
        ctl(fd, WDIOC_KEEPALIVE, 0);
        // printf("feed\n");
        sleep(3);
    }
    
    // disable the watchdog
    ctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD);
    close(fd);

    printf("watchdog is disabled\n");

    return 0;
}

代码编译很简单,香橙派自带gcc,只需要gcc wdt.c -o wdt就可以编译出可执行文件了。

程序运行后会自动启动看门狗,并会每隔3秒喂狗一次。若超过10秒没有喂狗,系统会自动重启。同时当进程收到SIGINT信号时,程序会禁用看门狗并正常退出运行。(SIGINT信号使用Ctrl+C就可以发出)

所以当系统挂掉以后,会导致这个看门狗喂狗程序停止运行,然后系统会自动重启。

另附上systemd.service文件(ExecStart需要自己修改成实际路径)

[Unit]
Description=a watchdog program for OrangePiZero2

[Service]
ExecStart=/home/orangepi/wdt/wdt
TimeoutStopSec=10
KillSignal=SIGINT

[Install]
WantedBy=multi-user.target