FULL-C: time functions

Tato stránka popisuje programovací jazyk FULL-C, který je dostupný na vybraných zařízeních SDS. 
Některá zařízení používají SDS-C, pro který máme návody jinde na této WiKi.

Funkce pro převod časových struktur

Zařízení SDS pracuje s různou reprezentací časové značky - ta může být poskytována a zpracována jako počet sekund od určeného data (tzv. EPOCH čas), nebo v "položkově-rozpadlé" formě ve formě jednotlivých časových údajů (hodina, minuta, sekunda atd.), uložených ve společné struktuře.

Za účelem převodu jsou k dispozici tyto funkce:


 POZOR - tyto C funkce jsou dostupné až pro firmware od 11.7.2022

 unsigned int mktime(void * timeptr);
         void gmtime(unsigned int * timer, void * timeptr);
         void localtime(unsigned int * timer, void * timeptr);

 POZOR - tato C funkce je dostupná až pro firmware od 17.11.2022

          int SDS_set_RTC(unsigned int epochtime, void * timeptr);


Struktura "tm"

Položky označené jako " * timeptr " jsou ukazatele na strukturu tm.

Struktura tm je pro účely FULL-C, definována takto:

 struct tm
 {
   int	tm_sec;		// seconds after the minute [0-60]  
   int	tm_min;		// minutes after the hour [0-59] 
   int	tm_hour;	// hours since midnight [0-23] 
   int	tm_mday;	// day of the month [1-31] 
   int	tm_mon;		// months since January [0-11] 
   int	tm_year;	// years since 1900 
   int	tm_wday;	// days since Sunday [0-6] 
   int	tm_yday;	// days since January 1 [0-365] 
   //
   int	tm_isdst;	// Daylight Saving Time flag 
   int	tm_gmtoff;	// offset from UTC in seconds
 };

Detaily:

  • tm_isdst : pouze pro čtení, vyplněno funkcí localtime() a gmtime(), hodnota je ignorována funkcí mktime() a SDS_set_RTC()
  • tm_gmtoff : pouze pro čtení, vyplněno funkcí localtime() a gmtime(), hodnota je ignorována funkcí mktime() a SDS_set_RTC()


Čas v SDS

SDS primárně využívá NTP pro pravidelnou časovou synchronizaci. SDS tedy pravidelně pomocí NTP aktualizuje svůj interní čas, který udržuje platný.

V základu, interně, je čas v SDS udržován jako hodnota EPOCH (UTC + 0), tedy počet sekund od pevného epoch data.

Uživatel může nastavit offset (v hodinách) vůči UTC a také zapnout automatický posun pro letní čas (dle pravidel CEST / CET).

Program může získat z SDS tento základní EPOCH čas (odpovídající 1:1 (bez posunů) tomu co přichází z NTP), nebo tzv. místní (LOKÁLNÍ) čas (což je upravený - posunutý - čas o uživatelem nastavený offset a také o automatický posun letního času).

Oba tyto časy jsou dostupné pro váš FC program, a modul SDS se stará aby oba byly trvale aktální.

V případě, že nechcete aby SDS využívalo NTP, lze NTP v nastavení vypnout. Čas pak musíte celému systému dodat sami, zápisem do příslušných indexů (viz seznam). Typicky se toto používá pokud získáváte čas z jiných zdrojů (GSM/LTE nebo např. LoRA síť), nebo pokud používáte externí zálohované RTC (neplatí pro BIG2-DP-DS84 které má interní RTC zálohované baterií).


Základní principu údržby času v SDS:

                                                                 +------------------+
                                                                 | přečtení obsahu  |
                                                                 | RTC po bootu SDS |  (pouze ale pokud v interním RTC je platný čas - pozor!)
                                                                 +------------------+
    ...                                                                 .
   .   .                                                                 .
   .  \./                                                                \./
+------------------------------------+    (dorazila odpověď)     +----------------+                +-----------+
|  pravidelné dotazy na NTP server   |    "epoch NTP UTC čas"    | interní HW RTC |    při čtení   | + offset  |
| (provádí SDS NTP klient)           |-------------------------->| v SDS modulu   | -------------->| + DST     |
+--+---------------------------------+                           +----+-----------+                +---+-------+
   |                                                                  |                                |
   +----> GET index 44 : stav                                         +----> GET index 139 : epoch     +----> GET index 4 : local time (modified epoch)
                                                                             (vrací aktuální UTC)                 indexy 5 .. 11 : local time (items)

Program tedy může sledovat, jestli se povedlo, přes NTP protokol, získat čas z NTP serveru. Dále může FULLC program sledovat, jestli po zapnutí se povedlo z interního HW RTC (vnitřní RTC v základu SDS) získat čas (např. pokud SDS prošlo restartem, je čas zachován).

Interní RTC v SDS automaticky udržuje běžící platný aktuální čas. Pravidelně je aktualizováno z NTP serveru (typicky vždy co 17 minut, je zaslán dotaz na server). Aktuální čas v době mezi dotazy na NTP server je právě udržován automaticky v bloku RTC. Z tohoto bloku je aktuální čas čten při jakémkoliv dotazu na čas.

Automatické dotazování na NTP server lze zakázat (viz nastavení ve webové administraci SDS). V takovém případě je povinností uživatele hodnotu do RTC nastavit svými prostředky.

V případě, že dojde k restartu SDS samotného (např. změna konfigurace), tedy pouze měkkému restartu (bez výpadku napájení), tak v RTC zůstává platný čas, který je pak k dispozici ihned po naběhnutí systému. Pokud však nebylo RTC včas naplněno, tak není platný čas k dispozici, a čeká se (typicky max. do 15 sekund od startu) na dotaz a odpověď od NTP serveru (která RTC naplní a to pak čas udržuje dál).

Upozorňuji na dva typy interních RTC v SDS modulu. Pouze modul typu "SDS-BIG2-DP-DS84" má RTC zálohované baterií, ostatní moduly mají RTC v provozu pouze po dobu kdy je modul napájen. Proto, pokud potřebujete funkci zálohovaného RTC i u ostatních modulů SDS, musíte připojit externí doplňující RTC (viz nabídka doplňujících modulů), a doplnit si potřebnou obsluhu do svého programu.

Paralelně s tímto je v SDS udržováno počítadlo "doby běhu od spuštění" tzv. UpTime. Toto počítadlo se nuluje při každém restartu firmware (libovolný důvod), a také při překročení hodnoty (počítá do 2^32).

UpTime počítadla jsou záměrně udržovány dvě nezávislé (ale jsou nulovány společně při startu - ale nejsou nulovány společně při přetečení jednoho z nich, to je důležitá informace). Jedno počítadlo je zvyšováno s krokem 1 msec, a druhé s krokem (co) 10 msec. Počítadlo s krokem 1 msec přeteče dříve než to s krokem 10 msec, takže se dá snadno identifikovat tato situace (porovnáním obou počítadel).

Využití UpTime je v programech kritické, zejména pro sledování běhu programu, pro funkce odpočtu (neblokující čekání), a také zejména pro výpisy ladících informací (krátká časová značka).


mktime()

Funkce mktime převede položkově rozpadnutý čas (obsah struktury tm) na epoch čas. Při převodu není aplikován jakýkoliv offset a není aplikován letní čas.

Epoch čas je často vyžadován např. pro známkování dat při přenosu po síti atd. - zejména protože se vždy vleze do 32 bitů, a tak zabírá minimum místa.


gmtime() a localtime()

Funkce převedou hodnotu ze vstupu (na který ukazuje "timer") na obsah struktury (na kterou ukazuje "timeptr").

gmtime() provede přímý "čistý" převod, tedy bez aplikace jakýchkoliv offsetů a posunů.

localtime() provede to samé co gmtime() ale s aplikací (1) letního času a za (2) nastaveného NTP offsetu. Letní čas je aplikován jen pouze pokud je právě aktivní (indikováno v tm_isdst, odpovídá hodnotě na indexu 65). Hodnota offsetu je zapsána do tm_gmtoff - jedná se o hodnotu nastavenou uživatelem v administraci (položka "NTP offset") - respektive lze číst jako proměnnou na indexu 26.

Pozn.: Aktuální systémový lokální čas (tedy UTC čas s aplikací letního času a offsetu) je k dispozici na indexu 4 - a rozpad pak na indexech 5 až 11, viz seznam všech položek.


Kde je funkce time() ?

Funkce time() není v SDS definována, protože UTC čas systému (tedy výstup takovéto funkce) získáte přímo čtením hodnoty na indexu 139.


Příklad

Následující příklad přečte UTC EPOCH čas ze systému (index 139) a převede to na jednotlivé položky do struktury tmp (definována jako: struct tm).

struct tm
 {
   int	tm_sec;		// seconds after the minute [0-60]
   int	tm_min;		// minutes after the hour [0-59]
   int	tm_hour;	// hours since midnight [0-23]
   int	tm_mday;	// day of the month [1-31]
   int	tm_mon;		// months since January [0-11]
   int	tm_year;	// years since 1900
   int	tm_wday;	// days since Sunday [0-6]
   int	tm_yday;	// days since January 1 [0-365]
   //
   int	tm_isdst;	// Daylight Saving Time flag
   int	tm_gmtoff;	// offset from UTC in seconds
 };

void main(void)
{
  unsigned int timeUTC;
  struct tm tmp;

  printf("time conversion test - localtime()\n");

  // get NTP UTC time
  timeUTC = SDS_get_u32(139);

  // or try to put any different value to "timeUTC" to test this

  // local conversion 
  localtime(&systemUTC, (void *)&tmp);

  printf("%02d:%02d:%02d\n", tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
  printf("%d.%d.%d\n", tmp.tm_mday, tmp.tm_mon+1, tmp.tm_year+1900);
}


SDS_set_RTC()

Společná funkce pro zápis času, do interního RTC v modulu SDS. Zavoláním této funkce jsou zapsány vždy všechny položky (tzn. celý čas a datum), nelze touto funkcí zapisovat jednotlivé položky samostatně.

Funkce má dva parametry, ale zpracován je vždy jen jeden z nich - je to čistě jen proto, aby se nemusely zavádět dvě různé funkce.

          int SDS_set_RTC(unsigned int epochtime, void * timeptr);
  • unsigned int epochtime = surová UTC+0 hodnota času (EPOCH) (tak jak by přišla z NTP serveru, bez jakýchkoliv aplikovaných offsetů).
  • void * timeprt = ukazatel na strukturu typu "struct tm" (viz výše)


Je-li předaná hodnota epochtime nenulová, je použita tato hodnota prioritně (a eventuální obsah timeptr je ignorován).

Hodnota epochtime je zpracována (uvnitř SDS) zcela identickým postupem, jako kdyby byla poskytnuta jako odpověď z NTP serveru. Tedy dojde k zápisu do RTC bloku, který dále drží běžící čas (vychází z tohoto nového nastavení).

Pokud je požadováno zpracovat obsah timeptr (tzn. epochtime je předán jako 0, a timeptr je platný ukazatel na strukturu), je timeptr v rámci této funkce převeden na epoch time, a ten je pak zapsán RTC bloku, který tedy tímto převezme všechny časové (a datumové) údaje a pokračuje od tohoto momentu s těmito údaji.

Finální výsledek (nastavení interního RTC v SDS) je tedy stejný, ať už je nový čas/datum zadán přes jeden nebo druhý parametr této funkce.

Návratové hodnoty:

  • 0 = vše OK
  • -1 = chyba (neprovedeno)