ScriptablePlugin umožňuje provádět nad piny složitější operace a dá se rovněž použít pro generování různých funkcí na výstupech. Celý plugin dokáže emulovat funkčnost většiny ostatních pluginů s vyjímkou těch, které přímo komunikují s HW (ISESCardPlugin, ISESProCardPlugin, PCI1202CardPlugin). Interface dostupný přímo z MeasureServeru je minimální a většina operací se provádí pomocí scriptu uloženého v samostatném souboru.
Pomocí tohoto dialogu jdou měnit základní parametry. Jakákoliv změna parametru vyžaduje restart MeasureServeru.
V dialogu MeasureServeru (viz. hlavní dokumentace) je nejdůležitější řádek pro volbu souboru se scriptem, který popisuje chování pluginu, dostupné piny a ostatní použité pluginy.
V případě, že script používá i jiné pluginy, je možné pomocí dalšího prvku umístěného v dialogu, nastavovat jejich parametry.
Scripty jsou textové soubory s koncovkou psc. Tyto scripty jsou načteny při startu MeasureServeru. Případné změny v nich provedené se projeví až při dalším spuštění MeasureServeru. Syntaxe použítá ve scriptu nejvíce připomíná programovací jazyk C s některými prvky z jiných jazyků. Všechny proměnné jsou reálná čísla (typ double v C), jiný datový typ není přímo podporovaný. Rozlišují se velká a malá písmena! Všechny operace prováděnné scriptem jsou synchronní s celým během serveru (dokud běží script, tak server nemůže provádět nic jiného).
Struktura scriptu je částečně fixní s tím, že většina částí je nepovinná, ale pokud jsou uvedeny tak musí být ve správném pořadí.
Struktura scriptu je následující:
Na většině míst v textu je možno používat komentáře uvedené znakem '#'. Cokoliv od tohoto znaku do konce řádku je ignorováno.
Hlavička má následující povinný formát
version 1.0 name example_generatorKde:
Popisuje jaké piny a z kterých pluginů budou použity. Piny se ve zbytku scriptu chovají jako proměnné. Zápis do takovéto proměnné zapíše hodnotu do pinu druhého pluginu. Čtení z takovéto proměnné přečte hodnotu z pinu druhého pluginu. Tato sekce má dvě části, jejichž pořadí je pevně dáno. První část definuje další pluginy, které jsou použity, včetně jména jejich konfigurace. Formát této části je následující:
using plugin_id "path_to_plugin" config_idKde:
using hw_lib "Plugins\ISESProCardPlugin.ldp" config1
Druhá část pak identifikuje piny z pluginů definovaných v první části, které jsou scriptem používány. Formát této části je následující:
import pin_id plugin_id "pin_name" [filter]Kde:
import output_a hw_lib "Write D/A 1"
Popisuje globální proměnné dostupné v celém scriptu. Proměnné vzniknou při startu serveru a nastaví se na hodnotu uvedenou v jejich definici. Následně může script jejich hodnoty libovolně číst a měnit. Formát definice proměnné je následující:
variable variable_id = valueKde:
variable sfrequency = 1.345
Tato část obsahuje výkonnou činnost scriptu. Celá je tvořena z bloků které mají následující syntaxi:
block_type [block_id] { operations }Kde:
Operace asociované s jedním z těchto handlerů se spustí, pokud nastane operace asociovaná s handlerem.
Operace asociované s on_each_second se spusti přibližně každou sekundu.
Operace asociované s on_user_change se spustí, když dojde ke změně uživatele nebo odpojení posledního uživatele.
V případě, že je v souboru scriptu definováno několik handlerů stejného typu, se všechny provedou v pořadí uvedeném ve scriptu.
Operace asociované s těmito piny se spustí pří přečtení nebo žápisu hodnoty pinu jménem block_id. Je možné mít v jednom scriptu pin_read i pin_write se stejným block_id, ale není možné mít ve scriptu několik pin_read/pin_write se stejným block_id.
Neexistuje žádné omezení z jakých pinů z ostatních pluginů je možné v rámci bloku číst nebo na které je možné zapisovat. Čtecí handler pro pin může klidně zapisovat na pin jiného pluginu. To umožňuje tvorbu generátorů signálu jak je uvedeno v kapitole Příklady
V případě, že běží handler pin_write, je dostupná speciální proměnna new_value s hodnotou, která se má zapsat do pinu.
V případě, že běží handler pin_read, je dostupná speciální proměnná time, která obsahuje čas v sekundách od posledního zápisu do tohoto pinu popřípadě od startu serveru pokud k žádnému zápisu dosud nedošlo. V případě, že odpovídající pin_write handler neexistuje, je zápis na tento pin ignorován, ale k restartu času dojde. Dále je zde dostupná speciální proměnná result, do níž by měl pin uložit hodnotu, která se vrátí jako hodnota přečtená z pinu. Defaultně je v této proměnné na začátku bloku uložena hodnota 0. Dále je dostupná proměnná reset_time, která (pokud je na konci nastavena na kladnou hodnotu), způsobi restart hodnoty time. V případě experimentů, jejichž server běží dlouhodoběji, je potřeba jednou za čas provést tento restart, jinak dojde ke ztrátě přesnosti času uloženého v proměnné time. V závislosti na HW počítače a velikosti hodnoty proměnné time může být čas vyjádřen až s přesností na desetinu milisekundy.
experiment foo { init { operations } on_sample plugin_id { operations } finalize { operations } }
Oproti běžným handlerům obsahují bloky experimentů speciální podporu pro předávání dat mezi bloky. Obsah dočasných proměnných (t0-t99) se přenáší mezi voláními bloků (například hodnota zapsaná do proměnné t50 v init bloku v ní bude dostupná i v průběhu on_sample bloku).
V blocích init a on_manual_sample je možné používat funkci write_output, která zapíše aktuální stav burst_out_* proměnných do seznamu dat posílaných na výstup v případě init bloku nebo do záznamu experimentu v případě on_manual_sample bloku. V případě init bloku je možné zapsat až 1000000 vzorků. V případě on_manual_sample je možné zapsat desetinásobek naměřeného množství HW vzorků (uložené v sample_count).
Blok on_sample/on_manual_sample na začátku dostane v proměnných sample_index, burst_in_time a burst_in_0-burst_in_7 parametry HW vzorku pro který je právě volán. Hodnota burst_out_time je nastavena na stejnou hodnotu jako burst_in_time. V rámci bloku je možné použít funkce sample a isample pro načtení parametrů i jiných naměřených vzorků. Volání jedné z těchto funkcí naplní hodnoty burst_in_time a burst_in_0-burst_in_7 hodnotami pro příslušný vzorek. Ostatní proměnné, hlavně burst_out_time a sample_index, zůstanou nezměněnné.
Operace asociované s blokem popisují, co se má stát, když se blok zpracovává. Jsou podporovány základní matematické operace jako je sčítání, odčítání, násobení, dělení, zbytek po dělení. Script také obsahuje několik goniometrických funkcí a nástroje pro tvorbu jednoduchých podmínek. V operacích je možné používat všechny proměnné uvedené v předchozích sekcích a dále je možno použít 100 dočasných proměnných, které platí pouze po dobu běhu bloku a na jeho začátku jsou nastavené na hodnotu 0.
Každý blok může mít libovolný počet operací.
Každá operace může být jedno z následujícího:
Přiřazení:
Y = expression ;
if ( if_expression ) { operations } [ else { operations } ]
while ( if_expression ) { operations }
exit ;
Zápis | Význam |
exit | Funkce ukončí běh bloku. |
stop | Funkce má význam pouze v on_sample/on_manual_sample bloku burst experimentu. Ukončí zpracování naměřených vzorků po dokončení zpracování aktualního vzorku. |
write_output | Funkce má význam pouze v on_sample/on_manual_sample/init bloku burst experimentu. Vygeneruje nový výstupní vzorek na základě aktualního stavu výstupních proměnných. |
sample( expression ) | Funkce má význam pouze v on_sample/on_manual_sample bloku burst experimentu. Načte do vstupních proměnných hodnotu vzorku s indexem ( sample_index + expression ). Hodnota se před přístupem zaokrouhlí na nejbližší celé číslo. Pokud je index mimo naměřený rozsah, použije se nejbližší naměřená hodnota. |
isample( expression ) | Podobné funkci sample, ale desetinná část je použita pro lineární interpolaci mezi dvěma vzorky, mezi které ( sample_index + expression ) padne. |
rotate( start, end, ammount ) | Orotuje dočasné proměnné (t0-t99) v rozsahu |
Expression je výraz, který může obsahovat libovolnou syntakticky platnou kombinaci proměnných, explicitních číselných konstant (např. 2.4), operací a funkcí uvedených níže. V příkladech uvedených níže jsou pismena A a B jména proměnných.
Znaménko | Operace | Příklad |
+ | Sčítání | 5 + A |
- | Odčítání | 5 - A |
- | Změna znaménka | -A |
* | Násobení | 5 * A |
/ | Dělení | A/3. V případě, že dojde k dělení nulou, vraci hodnotu 0 |
% | Zbytek po dělení | A % 3. V případě, že dojde k dělení nulou, vraci hodnotu 0 |
Funkce | Příklad | Popis |
clamp( x, minum, maximum ) | clamp( A, -5, 10.0 ) | Zajistí, aby vrácená hodnota byla pouze v uvedeném rozsahu. Pokud je minimum > maximum, je vrácena hodnota minimum. |
min( x, minum ) | min( A, 0.0 ) | Vrací minimum z obou hodnot. |
max( x, maximum ) | max( A, 0.0 ) | Vrací maximum z obou hodnot. |
pow( x, y ) | pow( A, 2.0 ) | Spočítá x^y |
cmp( x, treshold, result_a, result_b ) | cmp( A, 0.0, 1.0, 0.0 ) | Vraci result_a pokud x > treshold a jinak vraci result_b |
cmps( x, treshold, result_a, result_b ) | cmps( A, 0.0, 1.0, 0.0 ) | Vraci result_a pokud x >= treshold a jinak vraci result_b |
cmp( x, treshold ) | cmp( A, 0.0 ) | Zkratka pro cmp( x, treshold, 1.0, 0.0 ) |
cmps( x, treshold ) | cmps( A, 0.0 ) | Zkratka pro cmps( x, treshold, 1.0, 0.0 ) |
atan2( x, y ) | atan2( A, B ) | Vrací arc tangent v radiánech z hodnoty X / Y v radiánech včetně správného určení kvadrantu. |
asin( x ) | asin( A ) | Vrací arc sinus v radiánech z hodnoty oříznuté do rozsahu <-1,1>. |
acos( x ) | acos( A ) | Vrací arc cosinus v radiánech z hodnoty oříznuté do rozsahu <-1,1>. |
sin( x ) | sin( A ) | Vrací sinus hodnoty v radiánech |
cos( x ) | cos( A ) | Vrací cosinus hodnoty v radiánech |
remap( x, s0, s1, s2, d0, d1, d2 ) | remap( A, 100, 200, 300, 0, 0.5, 1.0 ) | Přemapuje hodnoty z rozsahu <s0,s1,s2> do rozsahu <d0,d1,d2> s tím že s1 se přemapuje na d1. Vstupní hodnoty mimo platný rozsah se oříznou do rozsahu <s0,s2> |
fraction( x ) | fraction( 3.5 ) | Vrací desetinou část vstupní hodnoty. Použitelné například pro generování signálu typu pila. |
floor( x ) | floor( 3.5 ) | Zaokrouhlí hodnotu na nejbližší nižší celé číslo |
ceil( x ) | ceil( 3.5 ) | Zaokrouhlí hodnotu na nejbližší vyžší celé číslo |
round( x ) | round( 3.5 ) | Zaokrouhlí hodnotu na nejbližší celé číslo |
abs( x ) | abs( -3.5 ) | Vrací absolutní hodnotu parametru |
Tento typ výrazu může být použit pouze v podmínce typu if. Oproti normálnímu výrazu je ještě rozšířen o následující užitečné zkratky.
Zkratka | Význam |
expression_a>expression_b | cmp( expression_a, expression_b ) |
expression_a>=expression_b | cmps( expression_a, expression_b ) |
expression_a<expression_b | cmp( expression_b, expression_a ) |
expression_a<=expression_b | cmps( expression_b, expression_a ) |
Plugin je možné použit pro generování signálu přes ISES následujícím postupem.
Ukázka jednoduchého scriptu generujícího sinusový přůběh s nastavitelnou frekvencí
version 1.0 name sin_signal # Importovani pinu do kterého budeme zapisovat. using card_lib "plugins\ISESProCardPlugin.ldp" card_config_1 import output card_lib "Write D/A 1" # Frequence generované křivky v HZ. variable set_frequency = 1.0 # Pin jehož čtení generuje výstup. pin_read generator { # Generovani hodnoty pro aktuální okamžik. result = sin( time * set_frequency * 6.28 ) * 2048 + 2048 ; } # Pin sloužící pro nastavení generované frequence. pin_read frequency { result = set_frequency ; } pin_write frequency { set_frequency = new_value ; }
# Script generujici sinusovou krivku nebo pilu s uzivatelsky nastavitelnou # frekvenci. # # Script ma nasledujici piny: # frequency .. cteni vraci aktualne nastavenou frekvenci v Hz. # frequency .. zapis nastavi novou frekvenci v Hz. # measured_value .. cteni vraci hodnotu prectenou z prvniho analogoveho vstupu # ISESu. # generator .. precteni tohoto pinu vygeneruje na vystup jednu hodnotu. Pro # spravnou funkci generatoru je potreba mit u tohoto pinu zapnuty # fastlog s rozume vysokou vzorkovaci frekvenci. # Verze scriptovaciho jazyka. version 1.0 # Nazev scriptu. Tato polozka se pouzije jako nazev pluginu v MeasureServeru. name example_generator # Reference na HW plugin, ktery se bude pouzivat pro vystup a vystup. using card_lib "plugins\ISESProCardPlugin.ldp" card_config_1 # Importovani pinu, do kterého budeme zapisovat vystup. import output card_lib "Write D/A 1" # Importovani pinu, ze ktereho budeme cist namerene hodnoty. import vstup_1 card_lib "Read A/D 1" # Typ generovane krivky. # # Hodnota >= 0.0 odpovida sinusove krivce. # Hodnota < 0.0 odpovida pile. variable output_type = 1.0 # Frequence generované křivky v Hz. variable generated_frequency = 1.0 # Promenna pouzita pro zastaveni generovani, kdyz neni komunikace # s klientem. variable watchdog_counter = 0.0 # Pin, jehož čtení generuje výstup. pin_read generator { # Generovani hodnoty pro aktuální okamžik. Pokud je generovani # zapnute, tak se spocita skutecna hodnota, jinak se pouzije # hodnota odpovidajici nule. if ( watchdog_counter > 0.0 ) { # Vygenerovani zvoleneho typu krivky jako hodnoty # v rozsahu <-1,1> if ( output_type >= 0.0 ) { t0 = sin( time * generated_frequency * 6.28 ) ; } else { t0 = fraction( time * generated_frequency ) * 2 - 1 ; } # Prepocet na vystupni rozsah 0 az 4095 (odpovida 12bitovemu rozliseni # ADDA karty a vystupnimu rozsahu <-5V,5V> tj. 0-4095 binarne) t0 = t0 * 2048 + 2048 ; # Vyslani spocitane hodnoty na vystup. Normalni experiment by mohl # spocitanou hodnotu vyslat i kdyz se nic negeneruje. Protoze vsak # ostatni ukazkove experimenty pouzivaji vystup, tak by takoveto # chovani tohoto prikladu zpusobilo nefunkcnost jejich vystupu. output = t0 ; } else { t0 = 2048 ; # Nasledujici radek vynuti restart promenne time. Vsechny vypocty v # tomto scriptu se provadeji pomoci 64bitovych cisel s pohyblivou # desetinou carkou. Dusledkem je, ze u prilis velkych hodnot dochází # ke ztrátě přesnosti hodnoty. Pokud by se reset neprovedl, experiment # by po delsi dobe zacal generovat cim dal "zubatejsi" krivku. reset_time = 1 ; } # Jeji vraceni jako hodnoty tohoto pinu. result = t0 ; } # Pin, jehoz precteni nacte hodnotu z prvniho HW vstupu. pin_read measured_value { result = vstup_1 ; } # Pin sloužící pro cteni a nastavovani generovane frekvence. pin_read frequency { result = generated_frequency ; # V ukazkove strance je applet, ktery periodicky cte tento pin (a zaroven # tento pin neni logovan), takze se tento pin cte prave kdyz je funkcni # spojeni s klientem. # Pri kazdem precteni se nastavi promena watchdog_counter na vhodne # zvolenou hodnotu. Hodnota teto promenne je kazdou sekundu snizena # o 1 (viz on_each_second nize) a generovani se zastavi pokud bude mensi # nez nula nebo rovna nule (viz. generator nahore). # Dusledkem je, ze generovani se zastavi pokud si tento pin nekdo neprecte # po odpovidajici pocet sekund. watchdog_counter = 5 ; } pin_write frequency { generated_frequency = new_value ; } # Pin slouzici na nastavovani typu generovaneho vystupu. pin_write type { output_type = new_value ; } # Nasledujici funkce je volana kazdou sekundu. on_each_second { # Odpocet casu do zastaveni generovani pokud uz toto nebylo zastaveno. if ( watchdog_counter > 0.0 ) { watchdog_counter = watchdog_counter - 1 ; } } # Kdyz se zmeni uzivatel, nastavime zpatky pocatecni frekvenci a # typ krivky. on_user_change { generated_frequency = 1.0 ; output_type = 1.0 ; }