classdef PLCCOSIM < matlab.System
    % PLCCOSIM Add summary here
    %
    % This template includes the minimum set of functions required
    % to define a System object with discrete state.

    % Public, tunable properties
    properties

    end

    properties(DiscreteState)
        CycleNum;
    end

    % Pre-computed constants
    properties(Access = private)
        UAObj;
        DeviceNode;
        Cycle_U;
        Cycle_Y;
        TestCycleNum;
        PreviousCycleNum;
    end

    methods(Access = protected)
        function setupImpl(obj)
            % Perform one-time calculations, such as computing constants
            % init opc UA server connection
            obj.UAObj = opcua('opc.tcp://localhost:4840');
            connect(obj.UAObj);
            obj.DeviceNode = findNodeByName(obj.UAObj.Namespace,'DeviceSet','-once');
            obj.Cycle_U = findNodeByName(obj.DeviceNode,'cycle_U');
            obj.Cycle_Y = findNodeByName(obj.DeviceNode,'cycle_Y');
            obj.TestCycleNum = findNodeByName(obj.DeviceNode,'testCycleNum');
            obj.PreviousCycleNum = findNodeByName(obj.DeviceNode,'previousCycleNum');                            
        end

        function y = stepImpl(obj,u)
            % Implement algorithm. Calculate y as a function of input u and
            % discrete states.            
            obj.CycleNum = obj.CycleNum+1;
            writeValue(obj.UAObj, obj.Cycle_U, u);
            writeValue(obj.UAObj, obj.TestCycleNum, obj.CycleNum);

            valueUpdated = false;
            for rct = 1:100
                previousCycleNumValue = readValue(obj.UAObj, obj.PreviousCycleNum);
                if previousCycleNumValue == obj.CycleNum
                    valueUpdated = true;
                    y = readValue(obj.UAObj, obj.Cycle_Y);             
                    break
                end
                pause(0.001)
            end        

            if ~valueUpdated
                error('not get the value for cycle number %d', obj.CycleNum);
            end                
        end

        function resetImpl(obj)
            % Initialize / reset discrete-state properties
            obj.CycleNum = 0;
            writeValue(obj.UAObj, obj.TestCycleNum, obj.CycleNum);
            writeValue(obj.UAObj, obj.PreviousCycleNum, obj.CycleNum);
        end
        
        function out = getOutputSizeImpl(obj)
            out = propagatedInputSize(obj,1);
        end
        
        function out = getOutputDataTypeImpl(obj)
            out = propagatedInputDataType(obj,1);
        end
      
        function c1 = isOutputComplexImpl(obj)
            c1 = false;
        end
   
        function c1 = isOutputFixedSizeImpl(obj)
            c1 = true;
        end
   
        function s = getDiscreteStateImpl(obj)
            s = obj.CycleNum;
        end
    end
end
