FULL-C tips and tricks

Z onlinetechnology.cz

Přejít na: navigace, hledání
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.

Různé tipy a triky

Zde jsou neseřazené tipy a triky, tak, vytvořené tak, jak jak postupem času dostáváme různé dotazy od uživatelů.


  • Dbejte na to, aby verze FC byla stejná jak pro překladač (FULLC.EXE) tak i pro vaše SDS. Pokud má vaše SDS starší firmware (a tedy starší verzi FC, například 0x06), zatímco překladač je novější (například FULLC.exe s verzí FC 0x08), tak SDS odmítne novější FC program spustit. Toto se řeší velmi snadno, a to aktualizací firmware ve vašem SDS.


  • I když proběhne překlad ve FULLC.EXE v pořádku, stále může váš FULL-C program obsahovat chyby - to se dozvíte teprve z konzole (web zařízení SDS: typicky 192.168.1.250/echo.htm), proto ji vždy průběžně kontrolujte !


  • Před provedením jakékoliv síťové komunikace ve FULL-C (např. odeslání emailu), vždy zkontrolujte stav, a to pomocí: status = SDS_get_u(27); (když je status==0 tak SDS nemá připojení - nezačínejte komunikaci, čekejte a testuje stav).


  • Pole pro uchování textů můžete přímo deklarovat, např. na zásobníku (stack) jako char text[128]; - nebo na haldě (heap), pro což využijte text = (char *)malloc(128); a free(text);text=0; funkce. Výběr z těchto možností je na vás (malé pole / malé texty jdou dát na zásobník, velké už patří do haldy).


  • Využijte 64-bitových proměnných (int64_t nebo uint64_t) tam, kde vám 32 bitů nestačí. Například pro počítadla, nebo výpočty s velkými čísly (nebo jen stačí že by měl být velký mezivýsledek a při použití 32-bit čísel by jste o něj "přišli").


  • Pro zjištění, jaký největší blok paměti (heap) lze v danou chvíli alokovat pomocí malloc() funkce, využijte funkci SDS_heap_stats() . Ačkoliv může být celková hodnota volné heap pamět velká, toto celkové volné místo je vždy roztroušeno na různé malé oddělené bloky (fragmentace) - a vždy lze alokovat jen po jednom bloku, a jeho největší možná velikost je zjistitelná právě ze zmíněné funkce.


  • Vždy když uvolníte paměť, nezapomeňte ihned ručně vynulovat daný uvolněný ukazatel. Příklad:
 // definice ukazatale
 void *ptr; 
 
 ...
 // alokujeme si pamet, pro priklad 32 bajtu
 ptr = malloc(32);
 
 // pamet na kterou ukazuje ptr lze ted pouzivat (pozor at nepristupujete mimo alokovany rozsah)
 ...
 
 // uz pamet nepotrebujeme, tak ji uvolnime:
 free(ptr); 
 ptr = 0;   // vzdy ihned za zavolanim free() nastavte ptr do nuly !!!
 
 ... 


  • Funkce printf() a puts() a putchar() zapisují do konzole (web zařízení SDS, typicky: 192.168.1.250/echo.htm), čehož lze využít pro ladění programu, nebo pro dálkový monitoring zařízení. Nicméně pro průběžné spolehlivé získávání hodnot a údajů z SDS nebo vašeho programu, je vhodně použít systém sdílených proměnných, nebo SNMP.


  • FULL-C používá právě přesně 32-bitů pro datový typ float. Počítejte s touto informací pro správné pochopení přesnosti práce s desetinnými čísly (omezené rozlišení dané 32bity). Pro většinu aplikací toto nepředstavuje problém, pokud ale chcete provádět složité výpočty s desetinnými čísly, je potřeba znát tato omezení. Přesné vysvětlení viz např. "Single-precision floating-point format".


  • Funkce printf() a sprintf() umí zpracovat float proměnné (%f), ale neumí je uživatelský formátovat (neumí např. %0.2f - ale umí jen základní %f, to znamená že vypíše úplně celou délku čísla se všemi pozicemi za tečkou, což může být i dost dlouhý text).


  • Nepoužívejte prázdný string (tj. "").

Tři příklady zakázaného kódu pro FULL-C:

 //
 char text1[10] = "";  // spatne !
 //
 strncpy(text2,"",10); // spatne !
 //
 sprintf(text2,"");    // spatne !


  • Před použítím některé z funkcí, které přistupují k serveru na Internetu, je vhodné provést volání dns_resolv() pro zjištění aktuální IP adresy (IP0.IP1.IP2.IP3) daného serveru, vždy před zavoláním konkrétní funkce (např. http_get() ).


  • Pokud některá z FULL-C funkcí selže (např. smtp_send() ohlásí přes smtp_send_status() chybu), tak je vhodné mít FULL-C program napsán tak, aby chvíli počkal, a pak to celé zkusil znovu. Při více selháních je pak potřeba provést další akci (oznámit chybu, zjsitit stav připojení k síti, atd.).


  • Přes FULL-C lze pouze číst kalibrační konstanty pro analogové vstupy. Pokud je chcete hromadně nastavit, použijte s výhodou 192.168.1.250/cgi_cfg_adc?xxxx volání (uživatel musí být přihlášen).


  • Každý FULL-C program může nastavit tzv. "brand" (uživatelskou značku / popisek) pro zařízení SDS, na kterém je spuštěn. Protože SDS je často dodáváno v rámci OEM pro další zástavbu do většího celku, může si finální systémový integrátor nastavit své doplňující texty (název firmy, odkazy na web, telefonní čísla na podporu, doplňující texty, informace o sériovém čísle atd.), které jsou pak zobrazeny v rámci stránek webové administrace zařízení SDS (login, welcome, atd.). Toto nastavení provádí FULL-C program zavolání SDS_set_a() s příslušným indexem a textem. Typicke se takový FULL-C kód dává na úplný začátek programu.


  • FULL-C program lze nachystat a vydat tak, že je "zablokován" tak aby fungoval pouze na jediném konkrétním vybraném SDS zařízení. Každé SDS má své unikátní sériové číslo (viz tabulka indexů pro SDSget_u() ), a FULL-C program může tuto hodnotu porovnat (s tím, co do FULL-C programu vloží autor programu). Toto uživatelské zablokování programu může předejít chybám, kdy by se např. nevhodný program nahrál omylem na jiný hardware. Pokud vydáváte FULL-C program prostřednictvím .FC souboru, kam zvolíte nepřiložit zdrojový .C kód, pak máte neprůstřelnou možnost zamezit použítí programu na jakémkoliv jiném SDS než jaké sami určíte (zdrojový kód nebude cílovému uživateli k dispozici, a navíc váš program otestuje sériové číslo daného SDS na shodu). Samozřejmě to znamená, že musíte zmíněné sériové číslo daného SDS zjistit předem, než vydáte program, aby jste to číslo mohli do programu vložit.


  • Pokud ve svém programu využíváte sériovou sběrnici RS485, dbejte na správné zapojení sběrnice. Naše fórum je plné příkladů, kdy autor programu řešil problém s RS485 a nakonec se ukázalo, že sběrnice byla špatně zapojená (přehozené A/B dráty, nezakončená rezistory, neuvedená do známeho klidového stavu přes rezistory atd.). Pro ověření programu je vždy dobré vzít pasivní "odposlech" sběrnice (osciloskop, osobní počítač) a zkontrolovat "překryv" (kdy více zařízení vysílá najednou, což je na RS485 kolize a poškození dat). Právě "překryv" je nejčastějším problémem způsobující poškození komunikace, hned po špatném nastavení komunikační rychlosti v programu. Vždy zkontrolujte svůj hardware, tj. celou sběrnici, je-li správně impedančně zakončena (nejvzdálenější konce) a zda-li jste správně zapojili oba klidové rezistory (pozor, na SDS-BIG tyto nejsou a musí se ručně doplnit "zvenku").


  • Pokud chcete přes sdílené proměnné (sv) přenášet čísla datového typu float (desetinná čísla), a pak je chcete například zobrazit na UserWEB webové stránce (a nebo přenést na server atd.), použijte následující trik. Vytiskněte obsah float čísla do Txx[] proměnné, pomocí sprintf(), nikoiv však s využitím %f - ale právě přes následující kód:
// definujeme si sdilenou promennou T00
char T00[32];
 
void FloatToT00(void)
{
 // vstupni float
 float xf;
 
 // pomocna promenna (presne 4 bajty, protoze "float" je ve FULL-C reprezentovan jako 32-bit)
 unsigned int xw;
 
 // zapiseme vzorovou hodnotu
 xf = 12.34;
 
 // ziskej 32bit obsah xf (= cteni 4 bajtu dat ktere reprezentuji dany float)
 xw = *(unsigned int *)&xf;
 // a zapis do T00, zarovnej vzdy na osm mist (at se to da pozdeji spravne zpracovat - prevest zpet na float)
 sprintf((char *)T00, "%08X", xw);
 
 // T00[] ted obsahuje "414570A4" (coz je hex reprezentace puvodni float hodnoty 12.34)
}

Pokud se po spuštění kódu pak podíváte např. na 192.168.1.250/shared.txt , tak tam uvidite toto: "T00|414570A4|" (krom jineho textu). S tím už pak v JavaScriptu není problém pracovat (převést zpět na float a korektně zobrazit nebo dále zpracovat). Řada přímých příkladu je k dispozici, stačí hledat na Internetu podle klíčových slov "javascript convert hex to float". Toto se řeší práve z důvodu že FULL-C printf funkce (a další podobné) umí jen %f ale bez dalších parametrů, takže tisknou float čísla na všechny místa za desetinnou tečkou, což je ve většině případů nežádoucí (při zobrazování na webových stránkách a podobně).

  • Přístupovat ke všem údajům ze sběrnic 1-Wire, ve FULL-C, je samozřejmě možné, je však potřeba vědět jak. Detaily viz stránka FULL-C_one_wire.


  • Pamatujte, že SDS-64 (viz SDS-BIG_varianty) má k diposizi pouze 64kB programové paměti (a SDS-128 má jen 128kB této paměti) - do které se musí vlézt váš přeložený FULL-C program, celý STACK a paměť HEAP. Toto omezení není dáno programově, ale právě použitým hardware v SDS, takže jej nelze jednoduše "obejít".


  • Vždy správně nastavte velikost STACKu - číselnou hodnotu nastavte v okně editoru zdrojového textu FULL-C. Pokud nastavíte hodnotu pro váš program jako moc malou, program nebude fungovat (při volání více funkcí může být pro nedostatek stacku ukončen). Příliš velká hodnota snižuje volnou pamět heap (pokud heap nepoužíváte, nastavte stack na vyšší hodnotu pro klid). Správnou hodnotu zjistíte určitým odhadem (podle velikosti a složitosti programu, podle toho kolik proměnných používáte a kolik parametrů se předává při volání funkcí, a kolik funkcí se v sobě volá). Nastavení je možné nechat automaticky odhadnou překladač, nebo jej můžete ručne zadat (odhad není přesný).


  • Inicializaci proměnných provádějte v kódu, nikoliv při deklaraci. Jde o to, že při inicializaci hodnot v proměnné či poli, provedené kódem, se spotřebuje zlomek stack paměti, oproti inicializace přímo při deklaraci. Stack paměti je vždy málo a je potřeba jí šetřit. Je to vlastnost FULL-C.

Příklad inicializace při deklaraci:

  unsigned int numbers[5] = {0,1,2,3,4}; // toto spotřebuje hodně stacku

Příklad identické inicializace kódem:

  // toto řešení je doporučené, nespotřebovává stack
  unsigned int numbers[5];
  number[0] = 0;
  number[1] = 1;
  number[2] = 2;
  number[3] = 3;
  number[4] = 4;

Nebo příklad odpovídající inicializace kódem:

  // toto řešení je doporučené, nespotřebovává stack
  unsigned int numbers[5];
  unsigned int i;
  for (i = 0; i < 5; i++) { number[0] = i; };


>>>>>>>>>>>> Následující informace je platná pouze pro firmware starší než 10.7.2017

  • SDS ukazuje aktuální využití své 64kB programové paměti, na webové stránce v administraci.
HEAP STATS: curalloc=1892, totfree=58632 maxfree=58632, nget=12 nrel=0
HEAP STATS: bc_locked=1120, stackTop=2984 (of 5000)

Jak to dékodovat: první řádek ukazuje celkové využití paměti a počet alokací a uvolnění:

curalloc  = celkem alokovaná paměť (heap malloc, a všechny interní FULL-C funkce a interní data v SDS)
totfree   = celkem zbývající volná (alokovatelná) heap pamět (součet všech volných heap fragmentů)
maxfree   = největší volný heap fragment, který je možné alokovat v jednom kuse
nget      = celkový počet alokací (volání malloc/calloc) (včetně vnitřních volání interních FULL-C funkcí v SDS)
nrel      = celkový počet uvolnění předchozích alokací (volání free() funkce)

Druhý řádek se vztahuje na FULL-C program samotný a jeho běh:

bc_locked = kolik bajtů paměti je využito (uzamčeno) pro 'bytecode' vašeho FULL-C (kolik si vzal samotný kód FULL-C programu v paměti)
stackTop  = kolik bajtů zásobníku (stacku) je v tento okamžik využito (pokud je to na limitu, víte, že musíte upravit nastavení při překladu)
(of X)    = kolik bajtů může nejvíce zásobník (stack) zabrat z celé paměti (nastaveno uživatelem před překladem)


>>>>>>>>>>>> Následující informace je platná pouze pro firmware 10.7.2017 (včetně) a novější (viz také SDS-BIG_varianty)

  • SDS ukazuje aktuální využití své 64kB nebo 128kB programové paměti, na webové stránce v administraci.
FC: VER 0x08, PROGMEM 128kB
MEM STATS:
- HEAP: used=(492 of 120675), totfree=120164 (biggest=65396), num(get=11,rel=0)
- STACK: used=(364 of 10004)
- BC: locked=(264+128+388)
- SYS: free=280

Jak to dékodovat: první řádek ukazuje informace o SDS:

VER        = verze FC
PROGMEM    = varianta hardware (64kB nebo 128kB celkové paměti pro program a data)

Druhý řádek ukazuje celkové využití paměti a počet alokací a uvolnění:

HEAP used  = celkem alokovaná paměť (heap malloc, a všechny interní FULL-C funkce a interní data v SDS)
totfree    = celkem zbývající volná (alokovatelná) heap pamět (součet všech volných heap fragmentů)
biggest    = největší volný heap fragment, který je možné alokovat v jednom kuse
nget       = celkový počet alokací (volání malloc/calloc) (včetně vnitřních volání interních FULL-C funkcí v SDS)
nrel       = celkový počet uvolnění předchozích alokací (volání free() funkce)

Druhý řádek se vztahuje na FULL-C program samotný a jeho běh:

STACK used = kolik bajtů zásobníku (stacku) je v tento okamžik využito (pokud je to na limitu, víte, že musíte upravit nastavení při překladu)

Třetí řádek se vztahuje na FULL-C program samotný a jeho běh:

BC locked  = kolik bajtů paměti je využito (uzamčeno) pro 'bytecode' vašeho FULL-C (kolik si vzal samotný kód FULL-C programu v paměti)

Čtvrtý řádek nemá pro FULL-C význam:

SYS        = interní hodnota



Další tipy a triky budou postupně doplňovány.

Osobní nástroje
Translate