function mojestream(block) %toto je první funkce, kterou si program vyvolá, slouží pouze k inicializaci funkce setup
  setup(block);

function setup(block) %zde se provádí základní nastavení s-funkce
%nastavení počtu vstupů a výstupů
block.NumInputPorts  = 1;
block.NumOutputPorts = 2;

%nastavení vlastnistí vstupů a výstupů jako převzaté
block.SetPreCompInpPortInfoToDynamic;
block.SetPreCompOutPortInfoToDynamic;
 
block.InputPort(1).DirectFeedthrough = true;
  
%nastavení časového kroku jako převzaté
block.SampleTimes = [-1 0];

%% Připojení LJ
ljasm = NET.addAssembly('LJUDDotNet');
ljudObj = LabJack.LabJackUD.LJUD;
[~, ljhandle] = ljudObj.OpenLabJackS('LJ_dtU3', 'LJ_ctUSB', '0', true, 0); %připojení prvního dostupného LJ
ljudObj.ePutS(ljhandle, 'LJ_ioPIN_CONFIGURATION_RESET', 0, 0, 0); %použití základního nastavení karty


%% Nastavení stream módu
%pro přehlednost nastavení rychlosti skenování, důležité pro udržování času
rychlsken = 10000; %pocetskenu musi byt v metode outputs nastaveno na 100, aby byl zachován cas. krok 0.01s;

%pro jistotu zastavíme jakýkoli stream, který by mohl na kartě běžet, např.
%vlivem žpatného ukončení programu
try
    ljudObj.eGet(ljhandle, 'LJ_ioSTOP_STREAM', 0, 0, 0);
catch
end

%nastavení frekvence skenování
ljudObj.AddRequestSS(ljhandle, 'LJ_ioPUT_CONFIG', 'LJ_chSTREAM_SCAN_FREQUENCY', rychlsken, 0, 0);

%nastavení velikosti paměti na kartě na 5 sekund záznamu (rychlost skenování * 2 kanály * 5 s).
ljudObj.AddRequestSS(ljhandle, 'LJ_ioPUT_CONFIG', 'LJ_chSTREAM_BUFFER_SIZE', rychlsken*2*5, 0, 0);

%Nastevení čekání na data na metofu SLEEP, zajišťující čekání na požadované
%množství dat a tím udržující reálný čas v programu
LJ_swSLEEP = ljudObj.StringToConstant('LJ_swSLEEP');
ljudObj.AddRequestSS(ljhandle, 'LJ_ioPUT_CONFIG', 'LJ_chSTREAM_WAIT_MODE', LJ_swSLEEP, 0, 0);

%resetování předchozích kanálů a nastavení streamovaných kanálů na AIN0 a AIN1
ljudObj.AddRequestS(ljhandle, 'LJ_ioCLEAR_STREAM_CHANNELS', 0, 0, 0, 0);
ljudObj.AddRequestS(ljhandle, 'LJ_ioADD_STREAM_CHANNEL', 0, 0, 0, 0);
ljudObj.AddRequestS(ljhandle, 'LJ_ioADD_STREAM_CHANNEL', 1, 0, 0, 0);

%% Zapnutí DAC1 jako zdroje napětí pro měřící obvod
ljudObj.AddRequestS(ljhandle, 'LJ_ioPUT_DAC', 1, 2, 0, 0);

%provedení žádaných úkonů
ljudObj.GoOne(ljhandle); 

%zapnutí streamu
ljudObj.eGetS(ljhandle, 'LJ_ioSTART_STREAM', 0, 0, 0);

%deklarace využívaných metod
block.RegBlockMethod('Outputs', @Output); 
block.RegBlockMethod('SetInputPortSamplingMode', @SetInpPortFrameData);
block.RegBlockMethod('Terminate', @Terminate);


  
function SetInpPortFrameData(block, idx, fd) %nastavení nutné pro práci s více vstupy, nebo výstupy
block.InputPort(idx).SamplingMode = fd;
block.OutputPort(1).SamplingMode  = fd;
block.OutputPort(2).SamplingMode = fd;

function Output(block) %zpracování vstupů a výstupů, komunikace s LJ

%opět pro přehlednost hodnota počtu žádaných hodnot (pro zachování
%správného času musí odpovídat
%(počet skenů)/(rychlost skenování) = fundamental sample time ze simulinku
pocetskenu = 100;
%% Zapnutí LJ a zahájení komunikace
%nutno provádět v každé metodě, S-funkce si totiž mezi metodami nepředává
%potřebné parametry
ljasm = NET.addAssembly('LJUDDotNet');
ljudObj = LabJack.LabJackUD.LJUD;
[~, ljhandle] = ljudObj.OpenLabJackS('LJ_dtU3', 'LJ_ctUSB', '0', true, 0); %připojení prvního dostupného LJ

%% předání požadovaného napětí na výstup DAC0
%získání požadovaného napětí ze vstupu do s-funkce
DAC0 = block.InputPort(1).Data; 

%přidání požadavku na zapsání získané hodnoty na pin DAC0
ljudObj.AddRequestS(ljhandle, 'LJ_ioPUT_DAC', 0, DAC0, 0, 0); 

%vykonání požadavku na změnu napětí
ljudObj.GoOne(ljhandle); 

%% Získání parametrů pro ovládání stream módu

%načtení všech parametrů pro IOType
typeIO = ljasm.AssemblyHandle.GetType('LabJack.LabJackUD.LJUD+IO'); 

%získání parametru GET_STREAM_DATA (sběr dat)
LJ_ioGET_STREAM_DATA = typeIO.GetEnumValues.Get(22);  

%načtení všech parametrů pro Channel
typeCHANNEL = ljasm.AssemblyHandle.GetType('LabJack.LabJackUD.LJUD+CHANNEL'); 

%získání parametru pro ALL_CHANNELS (pro všechny streamované kanály)
LJ_chALL_CHANNELS = typeCHANNEL.GetEnumValues.Get(99);  


%% čtení dat
%Vytvoření pole pro uložení dat (dostatečně velké pro včechna data, tedy
%požadovaná data*počet kanálů
data = NET.createArray('System.Double', 2*pocetskenu); 


%přečtení konkrétního množství dat (numScansRequested) a zapsání do
%vytvořeného pole (data) pomocí požadavku eGetPtr (funkce addRequest, Go, GetResult dohromady)
ljudObj.eGetPtr(ljhandle, LJ_ioGET_STREAM_DATA, LJ_chALL_CHANNELS, pocetskenu, data);

%v poli data jou data uložena jako [ch0(1), ch1(1), ch0(2), ch1(2)...]
%jeden kanál má sudý index a druhý lichý

%% Rozdělení dat pro jednotlivé kanály
%transformace dat do formátu srozumitelného pro MATLAB
Datamat = double(data);
%předvytvoření polí pro jednotlivé kanály (kvůli výůočetní rychlosti)
CH0 = zeros(1, pocetskenu/2); %ch0
CH1 = zeros(1, pocetskenu/2); %ch1
%rozdělení podle sudosti indexu
for i=1:pocetskenu
    if rem(i,2)
        CH0(floor(i/2 + 1)) = Datamat(i);
    else
        CH1(i/2) = Datamat(i);
    end
end

%zprůměrování hodnot získané při jednom kroku (alespoň částečné vyhlazení)
inAIN0 = mean(filloutliers(CH0,'center'));
inAIN1 = mean(filloutliers(CH1,'center'));

%předání hodnot získaných z LJ výstupům z S-funkce
block.OutputPort(1).Data = inAIN0;
block.OutputPort(2).Data = inAIN1;


function Terminate(~) %Procesy pro ukončení chodu
%% nastavení komunikace
ljudObj = LabJack.LabJackUD.LJUD;
[~, ljhandle] = ljudObj.OpenLabJackS('LJ_dtU3', 'LJ_ctUSB', '0', true, 0);

%% příkazy pro správné ukončení aplikace
ljudObj.eGetS(ljhandle, 'LJ_ioSTOP_STREAM', 0, 0, 0); %vypnutí streamu
ljudObj.AddRequestS(ljhandle, 'LJ_ioPUT_DAC', 0, 0, 0, 0); %vypnutí výstupu DAC0
ljudObj.AddRequestS(ljhandle, 'LJ_ioPUT_DAC', 1, 0, 0, 0); %Vypnutí výstupu DAC1
ljudObj.GoOne(ljhandle);
