//
// AOI_LLT8500_SAI
// Smart Automation Interface 2.2.0
//
// ======================================================
// 0. Internal state values
// ======================================================

InternalStateAcq_Ready := 1;
InternalStateAcq_ExposureActive := 2;
InternalStateAcq_RequestFlush := 3;
InternalStateAcq_ProcessingActive := 4;

InternalStateAcq_RequestReset := 100;
InternalStateAcq_Reset := 101;
InternalStateAcq_ManualMode := 150;
InternalStateAcq_AutomaticMode := 152;
InternalStateAcq_LoadUserSet := 200;
InternalStateAcq_ErrorLoadingUserSet := 202;
InternalStateAcq_RequestRegistration := 249;
InternalStateAcq_RegistrationRoutine := 250;
InternalStateAcq_ErrorRegistration := 252;

InternalStateEval_Ready := 1;
InternalStateEval_ReadResults := 2;
// ======================================================
// 1. Input Mapping RawIn -> UDTs
// ======================================================

In_Basis.Live := RawIn[0].0;
In_Basis.Reserved01 := RawIn[0].1;
In_Basis.EmitterOff := RawIn[0].2;
In_Basis.Reserved03 := RawIn[0].3;
In_Basis.CalibrationSuccess := RawIn[0].4;
In_Basis.Reserved05 := RawIn[0].5;
In_Basis.Reserved06 := RawIn[0].6;
In_Basis.CalibrationOn := RawIn[0].7;

In_Basis.Reserved10 := RawIn[1].0;
In_Basis.Reserved11 := RawIn[1].1;
In_Basis.Reserved12 := RawIn[1].2;
In_Basis.IO1 := RawIn[1].3;
In_Basis.IO2 := RawIn[1].4;
In_Basis.IO3 := RawIn[1].5;
In_Basis.IO4 := RawIn[1].6;
In_Basis.Reserved17 := RawIn[1].7;

CPS(RawIn[2], In_Basis.StateAcquisition, 1);
CPS(RawIn[3], In_Basis.UserSet, 1);
CPS(RawIn[4], In_Basis.ErrorCode, 1);

In_Smart.StateMachineMode := RawIn[6].0;
CPS(RawIn[7], In_Smart.StateEvaluation, 1);

CPS(RawIn[8], In_Results.Results[0], 64);


// ======================================================
// 2. Status outputs
// ======================================================

LiveBit := In_Basis.Live;
ErrorCode := In_Basis.ErrorCode;
InStateAcq := In_Basis.StateAcquisition;
InStateEval := In_Smart.StateEvaluation;
UserSet := In_Basis.UserSet;


// ======================================================
// 3. Operator inputs to output UDTs
// ======================================================

Out_Smart.MonitoringOn := bMonitoring;
Out_Basis.EmitterOff := EmitterOff;
Out_Basis.ResetError := ResetError;


// ======================================================
// 4. Reset request
// ======================================================

IF bReset THEN
    Out_Basis.Reset := 1;
    StateAcq := InternalStateAcq_RequestReset;
END_IF;


// ======================================================
// 5. Manual mode when automatic mode is off
// ======================================================

IF (NOT bAutomaticMode) AND
   (NOT Out_Basis.Reset) AND
   (StateAcq <> InternalStateAcq_RequestReset) AND
   (StateAcq <> InternalStateAcq_Reset) THEN

    Out_Smart.AutomaticMode := 0;
    StateAcq := InternalStateAcq_ManualMode;

END_IF;


// ======================================================
// 6. Error loading UserSet
// ======================================================

IF In_Basis.StateAcquisition = InternalStateAcq_ErrorLoadingUserSet THEN
    StateAcq := InternalStateAcq_ErrorLoadingUserSet;
END_IF;


// ======================================================
// 7. Acquisition State Machine
// ======================================================

IF StateAcq = InternalStateAcq_RequestReset THEN

    IF In_Basis.StateAcquisition = InternalStateAcq_RequestReset THEN
        Out_Basis.Reset := 0;
        bReset := 0;
        Out_Smart.AutomaticMode := 0;
        bAutomaticMode := 0;

        StateAcq := InternalStateAcq_Reset;
    END_IF;


ELSIF StateAcq = InternalStateAcq_Reset THEN

    IF In_Basis.StateAcquisition = InternalStateAcq_ManualMode THEN
        Out_Basis.ExecuteCalibration := 0;
        Out_Smart.Start := 0;
        Out_Smart.Flush := 0;
        Out_Smart.ResultsAck := 0;

        bAutomaticRegistration := 0;
        bInPosition_Start := 0;
        bFlush := 0;
        bUnloadPart := 0;

        FOR i := 0 TO 63 DO
            Results.Results[i] := 0;
        END_FOR;

        StateEval := InternalStateEval_Ready;
        StateAcq := InternalStateAcq_ManualMode;
    END_IF;


ELSIF StateAcq = InternalStateAcq_ManualMode THEN

    IF bAutomaticMode THEN
        Out_Smart.AutomaticMode := 1;
        Out_Basis.UserSet := nUserSet;

        StateAcq := InternalStateAcq_AutomaticMode;
    END_IF;


ELSIF StateAcq = InternalStateAcq_AutomaticMode THEN

    IF In_Basis.StateAcquisition = InternalStateAcq_LoadUserSet THEN
        StateAcq := InternalStateAcq_LoadUserSet;

    ELSIF In_Basis.StateAcquisition = InternalStateAcq_Ready THEN
        StateAcq := InternalStateAcq_Ready;
    END_IF;


ELSIF StateAcq = InternalStateAcq_LoadUserSet THEN

    IF In_Basis.StateAcquisition = InternalStateAcq_Ready THEN
        StateAcq := InternalStateAcq_Ready;
    END_IF;


ELSIF StateAcq = InternalStateAcq_ErrorLoadingUserSet THEN

    Out_Basis.UserSet := nUserSet;

    IF In_Basis.StateAcquisition = InternalStateAcq_LoadUserSet THEN
        StateAcq := InternalStateAcq_LoadUserSet;

    ELSIF In_Basis.StateAcquisition = InternalStateAcq_Ready THEN
        StateAcq := InternalStateAcq_Ready;
    END_IF;


ELSIF StateAcq = InternalStateAcq_RequestRegistration THEN

    IF In_Basis.StateAcquisition = InternalStateAcq_RegistrationRoutine THEN
        bAutomaticRegistration := 0;
        Out_Basis.ExecuteCalibration := 0;

        StateAcq := InternalStateAcq_RegistrationRoutine;
    END_IF;


ELSIF StateAcq = InternalStateAcq_RegistrationRoutine THEN

    IF In_Basis.StateAcquisition = InternalStateAcq_ErrorRegistration THEN
        StateAcq := InternalStateAcq_ErrorRegistration;

    ELSIF In_Basis.StateAcquisition = InternalStateAcq_Ready THEN
        StateAcq := InternalStateAcq_Ready;
    END_IF;


ELSIF StateAcq = InternalStateAcq_ErrorRegistration THEN

    IF bAutomaticRegistration THEN
        Out_Basis.ExecuteCalibration := 1;
        StateAcq := InternalStateAcq_RequestRegistration;
    END_IF;

END_IF;


// ======================================================
// 8. Discrete Measurement
// ======================================================

IF NOT In_Smart.StateMachineMode THEN

    IF StateAcq = InternalStateAcq_Ready THEN

        Out_Basis.UserSet := nUserSet;

        IF In_Basis.StateAcquisition = InternalStateAcq_LoadUserSet THEN
            StateAcq := InternalStateAcq_LoadUserSet;

        ELSIF bAutomaticRegistration THEN
            Out_Basis.ExecuteCalibration := 1;
            StateAcq := InternalStateAcq_RequestRegistration;

        ELSIF bInPosition_Start AND
              (In_Basis.StateAcquisition = InternalStateAcq_Ready) THEN

            bFlush := 0;
            Out_Smart.Start := 1;

            FOR i := 0 TO 39 DO
                Out_JSN.JSN[i] := 0;
            END_FOR;

            FOR i := 0 TO 39 DO
                IF i < sJSN.LEN THEN
                    Out_JSN.JSN[i] := sJSN.DATA[i];
                END_IF;
            END_FOR;

            StateAcq := InternalStateAcq_ExposureActive;
        END_IF;


    ELSIF StateAcq = InternalStateAcq_ExposureActive THEN

        IF bFlush AND
           (In_Basis.StateAcquisition = InternalStateAcq_ExposureActive) THEN

            Out_Smart.Flush := 1;
            StateAcq := InternalStateAcq_RequestFlush;

        ELSIF (In_Basis.StateAcquisition = InternalStateAcq_RequestFlush) OR
              (In_Basis.StateAcquisition = InternalStateAcq_ProcessingActive) OR
              (In_Basis.StateAcquisition = 5) THEN

            bUnloadPart := 1;
            Out_Smart.Start := 0;
            bInPosition_Start := 0;
            Out_Smart.Flush := 0;
            bFlush := 0;

            StateAcq := InternalStateAcq_ProcessingActive;
        END_IF;


    ELSIF StateAcq = InternalStateAcq_RequestFlush THEN

        IF (In_Basis.StateAcquisition = InternalStateAcq_RequestFlush) OR
           (In_Basis.StateAcquisition = InternalStateAcq_ProcessingActive) OR
           (In_Basis.StateAcquisition = 5) THEN

            bUnloadPart := 1;
            Out_Smart.Start := 0;
            bInPosition_Start := 0;
            Out_Smart.Flush := 0;
            bFlush := 0;

            StateAcq := InternalStateAcq_ProcessingActive;
        END_IF;


    ELSIF StateAcq = InternalStateAcq_ProcessingActive THEN

        IF In_Basis.StateAcquisition = InternalStateAcq_Ready THEN
            bUnloadPart := 0;
            StateAcq := InternalStateAcq_Ready;
        END_IF;

    END_IF;


    // ==================================================
    // Evaluation State Machine
    // ==================================================

    IF In_Basis.StateAcquisition = InternalStateAcq_ManualMode THEN
        Out_Smart.ResultsAck := 0;
        StateEval := InternalStateEval_Ready;
    END_IF;


    IF StateEval = InternalStateEval_Ready THEN

        IF In_Smart.StateEvaluation = 5 THEN
            Out_Smart.ResultsAck := 1;
            CPS(In_Results.Results[0], Results.Results[0], 64);

            StateEval := InternalStateEval_ReadResults;
        END_IF;


    ELSIF StateEval = InternalStateEval_ReadResults THEN

        IF In_Smart.StateEvaluation = 6 THEN
            Out_Smart.ResultsAck := 0;

            StateEval := InternalStateEval_Ready;
        END_IF;

    END_IF;


// ======================================================
// 9. Continuous Measurement
// ======================================================

ELSE

    IF StateAcq = InternalStateAcq_Ready THEN

        Out_Basis.UserSet := nUserSet;

        IF In_Basis.StateAcquisition = InternalStateAcq_LoadUserSet THEN
            StateAcq := InternalStateAcq_LoadUserSet;

        ELSIF bAutomaticRegistration THEN
            Out_Basis.ExecuteCalibration := 1;
            StateAcq := InternalStateAcq_RequestRegistration;

        ELSIF bInPosition_Start AND
              (In_Basis.StateAcquisition = InternalStateAcq_Ready) THEN

            Out_Smart.Start := 1;
            StateAcq := InternalStateAcq_ExposureActive;
        END_IF;


    ELSIF StateAcq = InternalStateAcq_ExposureActive THEN

        CPS(In_Results.Results[0], Results.Results[0], 64);

        IF NOT bInPosition_Start THEN
            Out_Smart.Start := 0;
            StateAcq := InternalStateAcq_Ready;
        END_IF;

    END_IF;

END_IF;


// ======================================================
// 10. Output Mapping UDTs -> RawOut
// ======================================================

RawOut[0].0 := Out_Basis.Reserved00;
RawOut[0].1 := Out_Basis.ResultsDisable;
RawOut[0].2 := Out_Basis.EmitterOff;
RawOut[0].3 := Out_Basis.Reset;
RawOut[0].4 := Out_Basis.ExecuteCalibration;
RawOut[0].5 := Out_Basis.AcquisitionDisable;
RawOut[0].6 := Out_Basis.InitCounters;
RawOut[0].7 := Out_Basis.CalibrationDisable;

RawOut[1].0 := Out_Basis.ResetError;
RawOut[1].1 := Out_Basis.Reserved11;
RawOut[1].2 := Out_Basis.Reserved12;
RawOut[1].3 := Out_Basis.Reserved13;
RawOut[1].4 := Out_Basis.Reserved14;
RawOut[1].5 := Out_Basis.Reserved15;
RawOut[1].6 := Out_Basis.Reserved16;
RawOut[1].7 := Out_Basis.Reserved17;

CPS(Out_Basis.Reserved2, RawOut[2], 1);
CPS(Out_Basis.UserSet, RawOut[3], 1);
CPS(Out_Basis.Reserved4, RawOut[4], 2);

RawOut[6].0 := Out_Smart.AutomaticMode;
RawOut[6].1 := Out_Smart.Start;
RawOut[6].2 := Out_Smart.Flush;
RawOut[6].3 := Out_Smart.ResultsAck;
RawOut[6].4 := Out_Smart.MonitoringOn;
RawOut[6].5 := Out_Smart.Reserved65;
RawOut[6].6 := Out_Smart.Reserved66;
RawOut[6].7 := Out_Smart.SingleTrigger;

RawOut[7] := 0;

CPS(Out_JSN.JSN[0], RawOut[8], 40);