% DMD (DEWETRON Measurement Data) MATLAB import prototype
% Copyright (c) Dewetron GmbH 2021
% R4.0 for dmd_reader_api 4.0 (Interface V1.1)
%********************************************************
% Reduce Matlab usage of RAM:
% Home-Preferences(Environment)-Matlab-Workspace-Matlab array size limit
%********************************************************
% Plot examples
% At the end of the script you can find plot examples, including an example
% on plotting the UTC time on your x-axis
%********************************************************
% Please refer to the manual to adjust the script accordingly before usage

clear;
clc;

%% Set filename and path
% Data files have to be stored in a folder named 'DataFile'

filename = 'DMD20_Marker&Header_Sow_Fast_Sweeps.dmd';

path = [pwd '\'];
dataPath = [path 'DataFile\'];
funcPath = [path 'functions'];
dllPath = [path 'dll\'];
hPath = [path 'include\'];
addpath(funcPath);

%% Define channels to be read in
% All channels can be read in -> not recommended for long datafiles or
%   files with many channels -> RAM overload is possible
% Define channel names which should be read in -> names must be the same as
%   in OXYGEN
% readChannels = 'all' or readChannels = [string('xxx'), string('yyy'), string('zzz')]

readChannels = 'all';
% readChannels = [string('Channel 1'), ...
%                 string('Channel 2'), ...
%                 string('Channel 3'), ...
%                 string('Channel 7'), ...
%                 string('DI 1'), ...
%                 string('DI 2'), ...
%                 string('DI 8')];

%% Define if reduced (background statistics) data should be read in
% See manual for more information about reduced data
% 1 = read reduced data; 0 = do not read reduced data

readReducedData = 0;

%% Set parameter for markers/headerfields

% 1 = read Markers/Headers; 0 = do not read Markers/Headers
readMarkers = 1;
readHeader = 1;

%% Check 64bit
if (strcmp(computer, 'PCWIN64') == 1) 
    DMDReaderFile = 'dmd_reader_api_x64'; 
else
    DMDReaderFile = 'dmd_reader_api';
end

%% Load dll and check Interface version
if ~libisloaded('dmdlib')
   loadlibrary([dllPath, DMDReaderFile, '.dll'], [hPath, 'dmd_reader_api_special.h'], 'alias', 'dmdlib');
end

% initialize with interface version
interfaceVersion = [1,1];
DMDReader_ErrorCode = calllib('dmdlib', 'DMDReader_Initialize', interfaceVersion(1), interfaceVersion(2));

if (DMDReader_ErrorCode ~= 0)
    error(['Init Error: ', num2str(DMDReader_ErrorCode)])
end

%% Open file
fileFullName = [dataPath filename];
file_handle = libpointer('voidPtr');
[DMDReader_ErrorCode, ~ , file_handle] = calllib('dmdlib', 'DMDReader_OpenFile', fileFullName, file_handle);

if (DMDReader_ErrorCode ~= 0)
    error(['Error: ', num2str(DMDReader_ErrorCode), ' reading File: ', fileFullName])
end

%% Get Markers and Header Fields
if readHeader || readMarkers == 1
    getMarkersAndHeader(file_handle, readHeader, readMarkers)
end

%% Get Recording start time/Timestamp 
% isUTC = 1: timestamp in UTC
% isUTC = 0: timestamp in local time
TimestampUTC = libstruct('DMDReader_TIMESTAMP_UTC');
p_TimestampUTC = libpointer('DMDReader_TIMESTAMP_UTC', TimestampUTC);
isUTC = int32(0);
[DMDReader_ErrorCode, file_handle, TimestampUTC] = calllib('dmdlib', 'DMDReader_GetMeasurementStartTime', file_handle, p_TimestampUTC.Value, isUTC);
if (DMDReader_ErrorCode ~= 0)
    error(['Error: ', num2str(DMDReader_ErrorCode), ' DMDReader_GetMeasurementStartTime'])
end

%% Get Number of Channels
% number of channels
numChannels = uint64(0);
[DMDReader_ErrorCode, file_handle, numChannels] = calllib('dmdlib', 'DMDReader_GetNumChannels', file_handle, 0, numChannels); %0 - get all available channels
if (DMDReader_ErrorCode ~= 0)
    error(['Error: ', num2str(DMDReader_ErrorCode), ' DMDReader_GetNumChannels'])
end

ChannelInfo = struct;
% counter for a correct index for struct ChannelInfo to save only specific channels
count = 0; 

%% Reading out data

%creating waitbar
f = waitbar(0,'Please wait... Loading data...');

for idx = 0:numChannels-1
   waitbar((double(idx+1)/double(numChannels)),f,'Please wait... Loading data...');

   % get channels
   channel_handle = libpointer('voidPtr');
   outNumChRet = 0;
   [DMDReader_ErrorCode, file_handle, channel_handle, ~] = calllib('dmdlib', 'DMDReader_GetChannels', file_handle, 0, idx, 1, channel_handle, outNumChRet);
   if (DMDReader_ErrorCode ~= 0)
       error(['Error: ', num2str(DMDReader_ErrorCode), ' DMDReader_GetChannels'])
   end
   
   % get channel information
   channelInfo = libstruct('DMDReader_CHANNELINFORMATION');
   p_channelInfo = libpointer('DMDReader_CHANNELINFORMATION', channelInfo);
   [DMDReader_ErrorCode, channel_handle, channelInfo] = calllib('dmdlib', 'DMDReader_GetChannelInformation', channel_handle, p_channelInfo.Value);
   if (DMDReader_ErrorCode ~= 0)
       error(['Error: ', num2str(DMDReader_ErrorCode), ' DMDReader_GetChannelInformation'])
   end
   
   % check if the special character Â is put in front of the unit
   is_special = true(size(channelInfo.unit));
   is_special(regexp(channelInfo.unit, 'Â')) = false;
   channelInfo.unit = channelInfo.unit(is_special);

   % compare defined channels 
   if any((readChannels == 'all')) || any(strcmp(channelInfo.name, readChannels))
       
   %saving channel information
   if any((readChannels == 'all'))
        ChannelInfo(idx+1).channels = channelInfo;
   elseif any(strcmp(channelInfo.name, readChannels))
       ChannelInfo(count+1).channels = channelInfo;
       count = count + 1;
   end
        
       % get sample type for current channel
       [sampleTypeData, sampleTypeReduced] = getSampleType(channel_handle);

     %% Read sweeps
       % read number of sweeps and sweeps
       % type = 1 for scaled data, type = 2 for reduced data
       [infoSweep, numDataSweeps] = readSweep(1, channel_handle, numChannels, idx);

     %% Read samples
       temp = struct ();

       switch sampleTypeData
           case 0 % invalid sample type
               error('Error: Invalid Sample Type')

           case 1 % analog/counter sample type
               temp.complete.time = [];
               temp.complete.data = [];

                for k = 0:numDataSweeps - 1
                    firstSampleIndex = infoSweep(idx+1).channels(k+1).sweep.firstSample; %infoSweep(ch number).channels(sweep number)
                    lastSampleIndex = infoSweep(idx+1).channels(k+1).sweep.lastSample;
                    numSamples = uint64(lastSampleIndex - firstSampleIndex + 1);

                    data_temp = readScaledValues(firstSampleIndex, numSamples, lastSampleIndex, channel_handle);
                    if(isempty(data_temp) ~= 1)
                        name = ['sweep', num2str(k+1)];
                        temp.(name) = data_temp;
                        temp.complete.time = vertcat(temp.complete.time, data_temp.time);
                        temp.complete.data = vertcat(temp.complete.data, data_temp.data);
                    end
                end % for k numDataSweeps
                name = matlab.lang.makeValidName(channelInfo.name);
                assignin ('base',name, temp);

               if sampleTypeReduced == 2 && readReducedData ==1 % reduced sample type
                    [~, ~] = readSweep(2, channel_handle, numChannels, idx, channelInfo);
               end % end if (sampleTypeReduced)

           case 3 % digital sample type
               temp.complete.time = [];
               temp.complete.data = [];
                for k = 0:numDataSweeps - 1
                    firstSampleIndex = infoSweep(idx+1).channels(k+1).sweep.firstSample;
                    lastSampleIndex = infoSweep(idx+1).channels(k+1).sweep.lastSample;
                    numSamples = uint64(lastSampleIndex - firstSampleIndex + 1);

                    [data_temp] = readDIValues(firstSampleIndex, numSamples, lastSampleIndex, channel_handle);
                    if(isempty(data_temp) ~= 1)
                        name = ['sweep', num2str(k+1)];
                        temp.(name) = data_temp;
                        temp.complete.time = vertcat(temp.complete.time, data_temp.time);
                        temp.complete.data = vertcat(temp.complete.data, data_temp.data);
                    end
                end % for k numDataSweeps

                name = matlab.lang.makeValidName(channelInfo.name);
                assignin ('base',name, temp);

           case 100 % scalar vector type
               temp.complete.time = [];
               temp.complete.data = [];
               for k = 0:numDataSweeps - 1
                   firstSampleIndex = infoSweep(idx+1).channels(k+1).sweep.firstSample;
                   lastSampleIndex = infoSweep(idx+1).channels(k+1).sweep.lastSample;
                   numTS = uint64(lastSampleIndex - firstSampleIndex + 1); 

                   [data_temp] = readVectorValues(sampleTypeData, firstSampleIndex, lastSampleIndex, numTS, channel_handle, maxDim);
                   if(isempty(data_temp) ~= 1)
                       name = ['sweep', num2str(k+1)];
                       temp.(name) = data_temp;
                       temp.complete.time = vertcat(temp.complete.time, data_temp.time);
                       temp.complete.data = vertcat(temp.complete.data, data_temp.data);
                   end
                end % for k numDataSweeps

               name = matlab.lang.makeValidName(channelInfo.name);
               assignin ('base',name, temp);

           case 101 % complex vector type
               temp.complete.time = [];
               temp.complete.real = [];
               temp.complete.imag = [];
               for k = 0:numDataSweeps - 1
                   firstSampleIndex = infoSweep(idx+1).channels(k+1).sweep.firstSample; %infoSweep(ch number).channels(sweep number)
                   lastSampleIndex = infoSweep(idx+1).channels(k+1).sweep.lastSample;
                   numSamples = uint64(lastSampleIndex - firstSampleIndex + 1); 

                   [data_temp] = readVectorValues(sampleTypeData, firstSampleIndex, lastSampleIndex, numSamples, channel_handle, maxDim);
                   if(isempty(data_temp) ~= 1)
                        name = ['sweep', num2str(k+1)];
                        temp.(name) = data_temp;
                        temp.complete.time = vertcat(temp.complete.time, data_temp.time);
                        temp.complete.real = vertcat(temp.complete.real, data_temp.real);
                        temp.complete.imag = vertcat(temp.complete.imag, data_temp.imag);
                   end
               end % for k numDataSweeps

               name = matlab.lang.makeValidName(channelInfo.name);
               assignin ('base',name, temp);

       end % for switch
   end % reading out all or only specific channels
end % for idx            
close(f) % close waitbar

%% Close file
% DMDReader_ErrorCode DMDREADER_EXPORT DMDReader_CloseFile (DMDReader_FileHandle file);
[DMDReader_ErrorCode, ~] = calllib('dmdlib', 'DMDReader_CloseFile', file_handle);
if (DMDReader_ErrorCode ~= 0)
   error(['Error: ', num2str(DMDReader_ErrorCode), ' DMDReader_CloseFile'])
end

%% Dispose and clear
DMDReader_ErrorCode = calllib('dmdlib', 'DMDReader_Dispose');
if (DMDReader_ErrorCode ~= 0)
   error(['Error: ', num2str(DMDReader_ErrorCode), ' DMDReader_Dispose'])
end

clear count
clear channel_handle
clear channelInfo
clear data_temp
clear dataPath
clear dllPath
clear DMDReader_ErrorCode
clear DMDReaderFile
clear file_handle
clear fileFullName
clear filename
clear firstSampleIndex
clear funcPath
clear headerfield
clear headerfieldPtr
clear hPath
clear idx
clear infoReducedSweep
clear infoSweep
clear interfaceVersion
clear isUTC
clear is_special
clear f
clear i
clear j
clear k
clear lastSampleIndex
clear markerEvent
clear markerEventPtr
clear maxDim
clear name
clear numChannels
clear numDataSweeps
clear numFields
clear numHeaderFields
clear numMarkers
clear numMarkers2
clear numReducedSweeps
clear numSamples
clear numTS
clear outNumChRet
clear p_channelInfo
clear p_TimestampUTC
clear readMarkers
clear readHeader
clear path
clear readChannels
clear readReducedData
clear sampleTypeData
clear sampleTypeReduced
clear temp

%% unload library
unloadlibrary('dmdlib');


%% Plot examples

% % Plotting data with UTC time on the x axis
% start_time = seconds(TimestampUTC.timeOfDay);
% start_time.Format = 'hh:mm:ss.SSSS';
% 
% samplerate = ChannelInfo(1).channels.sampleRate;
% delta = seconds(1 / samplerate);
% 
% % x must be the time vector of your channel to be plotted
% % y must be the data vector of your channel to be plotted
% x = Ch_SoD_GPS1_1.complete.time;
% y = Ch_SoD_GPS1_1.complete.data;
% len = length(x);
% 
% end_time = start_time + (delta * len);
% 
% samples = length(x);
% xData = linspace(start_time,end_time,samples);
% plot(xData, y)
% title('Scaled Data of Channel 1 - complete signal with UTC time')

% -------------------------------
% Suplots of the data
% subplot(2,1,1)
% plot(Channel1.sweep1.time, Channel1.sweep1.data)
% title('Scaled Data of Channel 1 - sweep 1')
% 
% subplot(2,1,2)
% plot(Channel1_Reduced.sweep1.time, Channel1_Reduced.sweep1.rms)
% title('Reduced RMS Data of Channel 1 - sweep 1')
% 
% subplot(2,1,1)
% plot(Channel1.complete.time, Channel1.complete.data)
% title('Scaled Data of Channel 1 - complete signal')
% 
% subplot(2,1,2)
% plot(Channel1_Reduced.complete.time, Channel1_Reduced.complete.rms)
% title('Reduced RMS Data of Channel 1 - complete signal')

