Watchdog é um dispositivo projetado para detectar e solucionar problemas de hardware. Geralmente, um timer é usado para isso, uma reinicialização periódica que impede que um sinal seja enviado para a reinicialização.
O servidor principal no Gentoo é usado principalmente por experimentos, no entanto, ele executa vários serviços que, se possível, devem estar disponíveis sem interrupção. Infelizmente, as consequências de alguns experimentos levam ao pânico do kernel, 100% da carga da CPU e outros problemas no momento mais inoportuno. Portanto, a ideia de adicionar cão de guarda há muito tempo exige atenção e finalmente se materializa neste dispositivo.Após uma inspeção minuciosa do que estava disponível e uma avaliação do tempo disponível, o cão de guarda montado com base no Arduino Nano foi a melhor opção. Uma lista de requisitos apareceu em torno do mesmo:- Iniciando e parando o daemon para trabalhar com um timer, uma ferramenta comum do SO (OpenRC).
- Cão de guarda próprio no dispositivo, no ATmega, você precisa usá-lo.
- O log de eventos no dispositivo para corrigir a reinicialização e o cronômetro.
- Sincronize a hora do dispositivo com o host para registrar a hora correta no log.
- Recebendo e exibindo o status do dispositivo e suas entradas de log.
- Limpando o log e redefinindo o dispositivo para seu estado original.
Assim, o "microscópio" foi encontrado, a "unha" está marcada ... você pode martelar.Hardware
A base do dispositivo foi o clone chinês Arduino Nano, fabricado com base no chip CH340. Os kernels recentes do Linux (testados desde a versão 3.16) têm um driver adequado, portanto o dispositivo é facilmente detectado como uma porta serial USB.Reinicialização indesejada do Arduino
Cada vez que o terminal é conectado, o Arduino é reiniciado. O motivo é que o terminal envia um sinal DTR (Data Terminal Ready), o que faz com que o dispositivo seja reinicializado. Assim, o Arduino IDE coloca o dispositivo em um modo para carregar esboços.Existem várias opções para solucionar o problema, mas apenas uma funcionou - é necessário instalar um eletrólito de 10µF (C1 no diagrama abaixo) entre os contatos RST e GND. Infelizmente, isso também bloqueia o download de esboços para o dispositivo.Como resultado - o esquema é o seguinte:
Desenhado usando o KiCadExplicações para o esquema- R1 — , PC817: (5V — 1.2V / 0.02A) = 190Ω, 180Ω.
- U2 — Arduino PC. , ( USB ), .
- JP1 — , . .
- 1 — , DTR.
- MB_RST, MB_GND — RESET , RST (GND). , .
- BTN_RST, BTN_GND — , , , , .
Loop de inicialização (reinicialização cíclica) ao trabalhar com o WDT
Os microcontroladores ATmega possuem um mecanismo de redefinição WDT (WatchDog Timer) embutido. No entanto, todas as tentativas de usar essa função levaram a um loop de inicialização, que poderia ser encerrado apenas desligando a energia.Pesquisas demoradas revelaram que os gerenciadores de inicialização da maioria dos clones do Arduino não oferecem suporte ao WDT. Felizmente, esse problema foi resolvido no gerenciador de inicialização alternativo Optiboot .Para fazer o flash do carregador de inicialização, você precisa de um programador que possa trabalhar no protocolo SPI, também é desejável que o IDE do Arduino conheça esse dispositivo "pessoalmente". Nesse caso, outro Arduino é ideal.Se usarmos o Arduino UNO, como programador, e a versão mais recente do Arduino IDE v1.6.5, o algoritmo será o seguinte:- boards-1.6.txt optiboot hardware/arduino/avr/boards.txt Arduino IDE.
- Arduino Uno, File → Examples → ArduinoISP.
- Arduino Nano :
Arduino Uno () | Arduino Nano (ICSP ) |
---|
5V → Vcc | GND → GND | D11 → MOSI | D12 → MISO | D13 → SCK | D10 → Reset |
| Pin1 (MISO) ← D12 | Pin2 (Vcc) ← 5V | Pin3 (SCK) ← D13 | Pin4 (MOSI) ← D11 | Pin5 (Reset) ← D10 | Pin6 (GND) ← GND |
|
- No IDE do Arduino, no menu Ferramentas, defina as configurações como na captura de tela:

- Selecione o item de menu Ferramentas → Gravar gerenciador de inicialização e verifique se o processo foi concluído sem erros.
Após esse procedimento, você precisará fazer o upload de esboços para o Arduino Nano, escolhendo as mesmas configurações - Placa : Optiboot em cpus de 32 pinos, Processador : ATmega328p, Velocidade da CPU : 16MHz.De solda
Em seguida, você precisa soldar tudo, para que pareça uma peça.
Aqui, eu precisava de um plugue USB devido ao fato de ter uma placa-mãe mini-ITX com apenas um conector para um par de USB2.0, necessários no painel frontal, e não havia nada para conectar ao bloco USB3.0. Se possível, esses dispositivos devem ser conectados diretamente à placa-mãe para que os fios não fiquem presos.A soldagem, por via de regra, não causa problemas, mas, neste caso, é utilizada uma placa de ensaio, que possui suas próprias especificidades.Como soldar faixas em uma tábua de pão( , ). .
:

Resultado:
pode parecer que alguns contatos estão mal soldados, mas isso é apenas um fluxo. O consumo de solda na tábua de pão é bastante grande, então tudo o que é possível é manchado com um fluxo aqui. De fato, este é um bom exemplo de como você não precisa deixar o produto após a solda. O fluxo deve ser lavado, caso contrário, pode haver problemas com a corrosão dos compostos. Vou acrescentar e vou lavar ... é melhor:
Parte do software
Objetivamente falando, o código deste projeto não é de interesse especial. Os introdutórios estão longe de serem extremos, e a arquitetura é descrita em uma frase: envie um comando - aguarde uma resposta. Por uma questão de ordem, descreverei aqui a principal funcionalidade e brevemente estarei nos pontos mais interessantes, do meu ponto de vista.Todo o código é publicado no GitHub, portanto, se você estiver familiarizado com o Bash e o C / C ++ (no contexto dos esboços do Arduino), a leitura neste momento poderá ser concluída. Se você estiver interessado, o resultado final pode ser encontrado aqui .Conexão Watchdog
Quando você conecta o watchdog, um arquivo de dispositivo é criado contendo o número de série. Se o sistema tiver outros dispositivos ttyUSB (no meu caso, um modem), há um problema com a numeração. Para identificar exclusivamente o dispositivo, você precisa criar um link simbólico com um nome exclusivo. Para isso, o udev foi projetado, o que provavelmente já existe no sistema.Primeiro, você precisa encontrar visualmente o cão de guarda conectado, por exemplo, observando o arquivo de log do sistema. Em seguida, substituindo / dev / ttyUSB0 pelo dispositivo desejado, escreva no terminal:udevadm info -a -p "$(udevadm info -q path -n /dev/ttyUSB0)"
Exemplo de saída looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.4/1-1.4:1.0/ttyUSB0/tty/ttyUSB0':
KERNEL=="ttyUSB0"
SUBSYSTEM=="tty"
...
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.4/1-1.4:1.0/ttyUSB0':
KERNELS=="ttyUSB0"
SUBSYSTEMS=="usb-serial"
DRIVERS=="ch341-uart"
...
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.4/1-1.4:1.0':
...
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.4':
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{idVendor}=="1a86"
ATTRS{idProduct}=="7523"
ATTRS{product}=="USB2.0-Serial"
...
Nesse caso, a regra ficará assim:ACTION=="add", KERNEL=="ttyUSB[0-9]*", SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="ttyrst-watchdog"
Você precisa colocá-lo em um arquivo separado no diretório /etc/udev/rules.d , por exemplo 51-ttyrst-watchdog.rules e dizer ao udev para recarregar as regras:udevadm control --reload-rules
A partir deste momento, ao conectar o watchdog, um link / dev / ttyrst- watchdog será criado no dispositivo desejado, que será usado posteriormente.Script Bash (ttyrst-watchdog.sh)
A comunicação com o watchdog é realizada a uma velocidade de 9600 baud. O Arduino funciona sem problemas com terminais em alta velocidade, mas os comandos para trabalhar com texto (gato, eco, etc.) recebem e enviam apenas lixo. É possível que esse seja um recurso apenas da minha cópia do Arduino Nano.Para o ciclo de reinicialização do timer principal e para as funções de linha de comando, um script é usado. O motivo é que ambos os componentes usam um recurso comum - o arquivo do dispositivo, e é necessário fornecer acesso síncrono a ele.A sincronização consiste essencialmente em um loop de espera:while fuser ${DEVICE} >/dev/null 2>&1; do true; done
e capture o dispositivo pelo tempo necessário:cat <${DEVICE}
Obviamente, esse esquema está sujeito a uma condição de corrida. Você pode lidar com isso de maneira adulta (por exemplo, para organizar uma fila de mensagens), mas, neste caso, é suficiente definir corretamente os tempos limite para garantir que você obtenha o resultado em um tempo aceitável. De fato, o script inteiro está trabalhando com tempos limite.A demonização (executando em segundo plano) é realizada usando o pacote OpenRC. Supõe-se que esse script esteja no arquivo /usr/local/bin/ttyrst-watchdog.sh , e o script OpenRC esteja em /etc/init.d/ttyrst-watchdog .Quando o daemon para, a desativação correta do cão de guarda é necessária. Para fazer isso, o script define o manipulador de sinal que requer conclusão:trap deactivate SIGINT SIGTERM
E aqui surge um problema - o OpenRC não pode parar o daemon, ou melhor, mas não com frequência.O fato é que o comando kill envia um sinal para o script e o programa sleep, que é usado para pausar o script, é executado em outro processo e não recebe o sinal. Como resultado, a função de desativação é ativada somente após a suspensão do sono, que é muito longa.A solução é iniciar o sono em segundo plano e aguardar a conclusão do processo no script:sleep ${SLEEP_TIME} & wait $!
Constantes básicas:WATCHDOG_ACTIVE - YES ou NO, respectivamente, enviam um sinal para reiniciar quando o timer é acionado ou não.WATCHDOG_TIMER - tempo em segundos durante o qual o timer está definido.SLEEP_TIME - tempo em segundos após o qual o timer deve ser reiniciado. Ele deve ser muito menor que WATCHDOG_TIMER, mas não muito pequeno, para não criar carga excessiva no sistema e no dispositivo. No tempo limite atual, um mínimo razoável é de aproximadamente 5 segundos.DEFAULT_LOG_LINES - o número de entradas recentes do log do dispositivo retornadas pelo comando de log padrão.Comandos de script:start- início do ciclo de reinicialização do timer principal. Você pode adicionar código de verificação adicional à função is_alive, por exemplo, para verificar a possibilidade de conexão via ssh.status - exibe o status do dispositivo.reset - redefine a EEPROM (dados de log) e reinicia o dispositivo para restaurar o watchdog ao seu estado original.log <número de entradas> - exibe o número especificado de entradas de log recentes.Esboço do Arduino (ttyrst-watchdog.ino)
Para compilar com êxito o esboço, você precisa de uma biblioteca de horário de terceiros , necessária para a sincronização de horário.Um esboço consiste em dois arquivos. Isso ocorre porque o IDE do Arduino não aceita as estruturas (struct) declaradas no arquivo principal, elas devem ser movidas para um arquivo de cabeçalho externo. Além disso, para declarar uma estrutura, a palavra-chave typedef não é necessária, provavelmente é até prejudicial ... depois de verificar as opções padrão, não consegui encontrar a sintaxe apropriada. O resto é mais ou menos C ++ padrão.As funções wdt_enable e wdt_reset funcionam com o watchdog integrado no microcontrolador. Após inicializar o WDT, o principal a lembrar é redefini-lo no loop principal e dentro dos loops de todas as operações demoradas.As entradas do log são gravadas na memória EEPROM não volátil, seu tamanho disponível pode ser especificado em logrecord.h, neste caso, é 1024. O log é feito na forma de um anel, o separador é uma estrutura com valores zero. O número máximo de entradas para 1 KiB EEPROM é 203.Um registro sobre o carregamento do dispositivo chega ao log somente após a sincronização de tempo. A sincronização é realizada ao mesmo tempo que o timer é reiniciado e antes que qualquer comando seja executado durante a inicialização do dispositivo. De outra maneira, não será possível comparar a hora correta com esse evento, e as informações sobre reinicializações do dispositivo, isoladamente do daemon em funcionamento, não são muito interessantes.
Isso é tudo, obrigado por assistir!Os arquivos de origem do projeto estão localizados no GitHub