Nel caso di applicazioni complesse su Raspberry Pi, torna utile verificare se l'NTP è sincronizzato con una sorgente e quindi si può fare affidamento sulla funzione
microtime(true) per le temporizzazioni.Nel caso in cui sia richiesta all'applicazione una risposta quasi-realtime (il kernel standard del Raspberry non consente l'utilizzo in hard-realtime), la chiamata periodica al comando
ntpstat introduce una latenza che porterebbe all'esecuzione a singhiozzo del programma.La soluzione adottata è quella di creare un file su filesystem
tmpfs, che risiede in RAM, che viene aggiornato da un processo separato dal programma principale, il quale a sua volta verificherà il contenuto del file per sapere se l'NTP è sincronizzato oppure no. La lettura del file è molto più veloce e di durata prevedibile rispetto all'esecuzione di ntpstat, tanto da poter essere chiamata ad ogni ciclo del programma.Per prima cosa bisogna creare un filesystem tmpfs. Creiamo il mountpoint:
$ sudo mkdir /mnt/pirun1/
Il filesystem dovrà essere montato prima dell'avvio dello script, è consigliabile aggiungere una riga a /etc/fstab:tmpfs /mnt/pirun1 tmpfs size=256k
ntp dovrà essere installato e configurato, anche ntpstat dovrà essere installato.Lo script creerà il file
/mnt/pirun1/NtpSync, che conterrà "1" se NTP è in sync, "0" in caso contrario, può essere lanciato in background o con screen (i.e. in /etc/rc.local) e dovrà restare sempre in esecuzione.
<?php
error_reporting(E_ALL);
# Apro in scrittura il file su tmpfs
# se non esiste lo crea
$fhandle = fopen("/mnt/pirun1/NtpSync", "c");
# La scrittura dello stato avviene solo in caso di acquisizione
# o perdita del sync, per risparmiare risorse
# Lo stato del ciclo precedente viene salvato nella variabile:
$LastValue = 2;
# Inizializzo a 2 in modo che poi, confrontata con 1 o 0 sia sempre falsa e
# faccia scrivere sempre il file temporaneo all'avvio dello script;
while (true) {
system("ntpstat > /dev/null 2> /dev/null", $return_var);
/*
* Non mi interessa l'output di ntpstat, la solo la variabile di ritorno:
* è =0 se è in sync, !=0 se è fuori sync
*
* Oltre a definire una variabile per identificare lo stato synced/unsynced,
* imposto l'intervallo di controllo: se sono in sync, posso accettare
* un ritardo nella segnalazione (l'orario non sarà immediatamente sbagliato),
* ma quando vado in sync lo devo sapere in tempi brevi.
*/
if ($return_var === 0) {
$IsSynced = 1;
$PollingInterval = 1000000;
} else {
$IsSynced = 0;
$PollingInterval = 20000;
}
# Se cambia lo stato, il file viene aggiornato.
if ($IsSynced <> $LastValue) {
fseek($fhandle, 0);
if ($IsSynced === 1) {
fwrite($fhandle, "1");
LogRow("In sync" . PHP_EOL);
} else {
fwrite($fhandle, "0");
LogRow("Out of sync" . PHP_EOL);
}
}
$LastValue = $IsSynced;
usleep($PollingInterval);
}
function LogRow($text) {
echo (date("c") . " " . $_SERVER["SCRIPT_NAME"] . " - " . $text);
}