aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/CalibrationDataVM.cs
blob: 403494a8ebf64e491202978d5c1ed93b1c8ffce6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.BL.Entities;
using Tango.Core;
using Tango.SharedUI;

namespace Tango.MachineStudio.RML.ViewModels
{
    public class CalibrationDataVM : ExtendedObject
    {
        private LiquidType _liquidType;

        public LiquidType LiquidType
        {
            get { return _liquidType; }
            set { _liquidType = value; RaisePropertyChangedAuto(); }
        }

        private IdsPack _idsPack;

        public IdsPack IdsPack
        {
            get { return _idsPack; }
            set { _idsPack = value; RaisePropertyChangedAuto(); }
        }

        private ObservableCollection<CalibrationDataPointVM> _calibrationPoints;

        public ObservableCollection<CalibrationDataPointVM> CalibrationPoints
        {
            get { return _calibrationPoints; }
            set { _calibrationPoints = value; RaisePropertyChangedAuto(); OnCalibrationPointsChanged(); }
        }

        private void OnCalibrationPointsChanged()
        {
            if (CalibrationPoints != null)
            {
                CalibrationPoints.CollectionChanged -= CalibrationPoints_CollectionChanged;
                CalibrationPoints.CollectionChanged += CalibrationPoints_CollectionChanged;

                SetIndices();
            }
        }

        private void CalibrationPoints_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            SetIndices();
        }

        private void SetIndices()
        {
            if (CalibrationPoints != null)
            {
                int index = 1;
                foreach (var p in CalibrationPoints)
                {
                    p.Index = index++;
                }
            }
        }

        private CalibrationDataVM()
        {
            CalibrationPoints = new ObservableCollection<CalibrationDataPointVM>();
        }

        public CalibrationDataVM(IdsPack pack) : this()
        {
            IdsPack = pack;
            LiquidType = pack.LiquidType;
        }

        public CalibrationDataVM(LiquidType liquidType) : this()
        {
            LiquidType = liquidType;
        }
    }
}
/*
 * ThreadLoad.c
 *
 *  Created on: Jan 16, 2019
 *      Author: shlomo
 */
#include <DataDef.h>
#include "include.h"
#include "thread_ex.h"

#include "Common/SWUpdate/FileSystem.h"

#include "StateMachines/Printing/PrintingSTM.h"

#include "Modules/thread/thread.h"
#include "Modules/Control/control.h"
#include "Modules/General/process.h"
#include "Modules/control/pidalgo.h"

#include "Modules/heaters/heaters_ex.h"
#include "StateMachines/Initialization/InitSequence.h"

#include "PMR/Hardware/HardwareMotor.pb-c.h"
#include "PMR/Hardware/HardwareMotorType.pb-c.h"
#include "PMR/Hardware/HardwareDancerType.pb-c.h"
#include "PMR/Printing/ProcessParameters.pb-c.h"

#include "drivers/Flash_Memory/fatfs/ff.h"
#include "drivers/I2C_Communication/DAC/Blower.h"
#include "drivers/SSI_Comm/Dancer/Dancer.h"
#include "drivers/motors/motor.h"

#include "PMR/Stubs/StubHeatingTestRequest.pb-c.h"
#include "PMR/Stubs/StubHeatingTestResponse.pb-c.h"
#include "PMR/Stubs/StubHeatingTestPollRequest.pb-c.h"
#include "PMR/Stubs/StubHeatingTestPollResponse.pb-c.h"

//#include <stdint.h>
//#include <stdbool.h>

/*    typedef enum
    {
        0 THREAD_LOAD_INIT,
        1 THREAD_LOAD_REDUCE_HEAT,                           //HEATERS OFF, DRYER BLOWER OFF, BLOWER LOW,
        2 THREAD_LOAD_SET_LOAD_ARM_TO_START_POSITION,        //USE NOTATION HOW MANY ROTATIONS IN THE DRYER, OR CHECK AGAINST STOPPER. MOVE SLOWLY
        3 THREAD_LOAD_CENTER_HEAD_ROCKERS,                   //puthead cleaning rockers to middle position
        4 THREAD_LOAD_OPEN_COVERS,                           //OPEN DYEING HEAD COVER AND DRYER LID
        5 THREAD_LOAD_LIFT_DANCERS,
        6 THREAD_LOAD_LIFT_ROCKERS,                          //MACHINE IS READY. SEND MESSAGE, START TIMER TO CLOSE LIDS, WAIT FOR OPERATOR RESPONSE
        7 THREAD_LOAD_INITIAL_TENSION,                       //CHECK SPOOL PRESENCERUN WINDER UNTIL BREAK SENSOR IS IDENTIFIEING MOVEMENT FOR A SECOND
        8 THREAD_LOAD_CLOSE_ROCKERS,
        9 THREAD_LOAD_CLOSE_DANCERS,                         //SEND DANCER MOTORS TO PRESET LOCATION, CHECK THAT THE DANCERS ARE ON THE THREAD
        10 THREAD_LOAD_CLOSE_LIDS,
        11 THREAD_LOAD_JOG_FEEDER_TO_MIDDLE_POINT,           //JOG THE FEEDER MOTOR UNTIL THE FEEDER DANCER IS AT MIDDLE POSITION
        12 THREAD_LOAD_DRYER_LOADING,                        //START FEEDER PID, ROTATE LOADING ARM COUNTER THREAD DIRECTION X CIRCLES ACCORDING TO RML. FEEDER SPEED IS 40
                                                             //KEEP NOTATION HOW MANY ROTATIONS IN THE DRYER
        13 THREAD_LOAD_RESUME_HEATING,
        14 THREAD_LOAD_JOG_THREAD,                           //JOG THREAD SHORTLY TO MAKE SURE SPOOL IS RUNNING. REPORT END OF LOADING
        15 THREAD_LOAD_END
    }THREAD_LOAD_STAGES_ENUM;*/
    THREAD_LOAD_STAGES_ENUM LoadStages = THREAD_LOAD_INIT;
    ProcessParameters ProcessParametersClear,ProcessParametersRecover;

    int32_t keepmicrostep;
    int32_t keepkvalrun,keepkvalhold;
    uint8_t CallbackCounter = 0;
    uint8_t TimeoutsCounter = 0;

    uint8_t NumberOfDrierLoaderCycles = 0;
    uint32_t status = OK;
    uint32_t LoadingControlId = 0xFF,PullerControlId = 0xFF,WinderControlId = 0xFF;
    uint32_t ThreadLoadStateMachine( THREAD_LOAD_STAGES_ENUM LoadStages);
    uint32_t ThreadLoadControlCBFunction(uint32_t index, uint32_t ReadValue);
    uint32_t Thread_Load_Dryer_UnLoading(void);

    typedef struct
    {
        uint32_t LoadArmRounds;
        uint32_t LoadArmBackLash;
    }LoadArmInfoStruc;
    LoadArmInfoStruc LoadArmInfo;
    char LoadArmPath[50] = "0://SysInfo//LoadArm.cfg";

    //RUN MOTOR TO SWITCH WITH TIMEOUT
    //RUN MOTOR TO BREAK SENSOR
    //RUN MOTOR TO DANCER LOCATION (POOLER GOES TO THE OTHER DIRECTION)

    //RUN MOTOR A FULL CYCLE
    //RUN A MOTOR NUMBER OF STEPS
    //RUN CONTROL FOR A SINGLE DANCER
    bool ThreadLoadingActive(void)
    {
        if ((LoadStages > THREAD_LOAD_INIT)&&(LoadStages < THREAD_LOAD_END))
            return true;
        else
            return false;
    }
    uint32_t Thread_Load_Init(void)
    {
        void* buffer = NULL;
        uint32_t Bytes = 0;
        FRESULT Fresult = FR_OK;
        REPORT_MSG(LoadStages, "Thread Load State Machine step");

        LoadArmInfo.LoadArmBackLash = 5;
        LoadArmInfo.LoadArmRounds = 0xFF;
        Fresult = f_mkdir(SW_INFO_DIR);
        if ((Fresult == FR_OK)||(Fresult == FR_EXIST))
        {

            Fresult = FileRead(LoadArmPath, &Bytes, &buffer);
            if (Fresult == FR_OK)
            {
               if (Bytes>=sizeof(LoadArmInfo))
                   memcpy (&LoadArmInfo,buffer,sizeof(LoadArmInfo));
               free (buffer);
            }
        }

        Report("Thread_Load_Init",__FILE__,__LINE__,LoadArmInfo.LoadArmBackLash,RpMessage,LoadArmInfo.LoadArmRounds,0);
        StopInitSequence();
        memcpy (&ProcessParametersRecover,&ProcessParametersKeep,sizeof(ProcessParameters));
        //NumberOfDrierLoaderCycles = loadLoadArmParameters();
        LoadStages++;
        ThreadLoadStateMachine(LoadStages);

        return OK;
    }
    uint32_t Thread_Load_Reduce_Heat(void)
    {

        //Heaters Off, Dryer Blower Off, Blower Low,
        REPORT_MSG(LoadStages, "Thread Load State Machine step ");
        memcpy (&ProcessParametersClear,&ProcessParametersKeep,sizeof(ProcessParameters));
        ProcessParametersClear.dryerzone1temp = 0;
        ProcessParametersClear.dryerzone2temp = 0;
        ProcessParametersClear.dryerzone3temp = 0;
        ProcessParametersClear.mixertemp      = 0;
        ProcessParametersClear.headzone1temp  = 0;
        ProcessParametersClear.headzone2temp  = 0;
        ProcessParametersClear.headzone3temp  = 0;
        ProcessParametersClear.headzone4temp  = 0;
        ProcessParametersClear.headzone5temp  = 0;
        ProcessParametersClear.headzone6temp  = 0;
        ProcessParametersClear.dyeingspeed = 40;
        ProcessParametersClear.dryerbufferlength = ProcessParametersKeep.dryerbufferlength;
        if (HandleProcessParameters(&ProcessParametersClear)!= OK)
        {
            LOG_ERROR (LoadStages, "Thread_Load_Init failed");
        }
        else
        {
            Turn_the_Blower_On();//Turn on with the Default_Voltage
            if (BlowerCfg.heatingvoltage)
                Control_Voltage_To_Blower(BlowerCfg.heatingvoltage);
            else
                Control_Voltage_To_Blower(BlowerCfg.voltage-500);
            Control_Dryer_Fan(STOP,75);//use START or STOP,  0 - 100%
            LoadStages++;
            ThreadLoadStateMachine(LoadStages);
        }
        return OK;
    }
    uint32_t Thread_Load_Set_Load_Arm_To_Start_Position_Callback(uint32_t deviceID, uint32_t BusyFlag)
    {
       // Report("Thread Load State Machine Callback.",__FILE__,__LINE__,LoadStages,RpMessage,NumberOfDrierLoaderCycles,0);

        /*NumberOfDrierLoaderCycles--;
        if (NumberOfDrierLoaderCycles)
        {
            Report("Thread_Load_Set_Load_Arm_To_Start_Position_Callback",__FILE__,__LINE__,LoadStages,RpMessage,NumberOfDrierLoaderCycles,0);
            status |= MotorMoveWithCallback(HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM, (1-MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].directionthreadwize),
                                            MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulseperround, Thread_Load_Set_Load_Arm_To_Start_Position_Callback,1000);
        }
        else*/
        {
            Report("Thread_Load_Set_Load_Arm_To_Start_Position_Callback",__FILE__,__LINE__,LoadStages,RpMessage,CallbackCounter,0);
            //storeLoadArmParameters();
            SetMotHome(HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM);  //set this point as the spool home
            LoadStages++;
            ThreadLoadStateMachine(LoadStages);
        }
        return OK;
    }
    uint32_t Thread_Load_Set_Load_Arm_To_Stopper_Callback(uint32_t deviceID, uint32_t BusyFlag)
    {

        if(PullerControlId != 0xFF)
        {
            MotorStop(ThreadMotorIdToMotorId[POOLER_MOTOR],Hard_Hiz);
            RemoveControlCallback(PullerControlId, ThreadLoadControlCBFunction );
            PullerControlId = 0xFF;
        }
        if(WinderControlId != 0xFF)
        {
            MotorStop(ThreadMotorIdToMotorId[WINDER_MOTOR],Hard_Hiz);
            RemoveControlCallback(WinderControlId, ThreadLoadControlCBFunction );
            WinderControlId = 0xFF;
        }
        /*Task_sleep(5)
        MotorStop(ThreadMotorIdToMotorId[FEEDER_MOTOR],Hard_Hiz);
        MotorStop(ThreadMotorIdToMotorId[FEEDER_MOTOR],Hard_Hiz);*/

        MotorStop(HARDWARE_MOTOR_TYPE__MOTO_DRYER_DRIVING,Hard_Hiz);

//        Report("Thread Load State Machine Callback.",__FILE__,__LINE__,LoadStages,RpMessage,NumberOfDrierLoaderCycles,0);
        CallbackCounter = 0;
        Report("Thread_Load_Set_Load_Arm_To_Stopper_Callback",__FILE__,__LINE__,LoadStages,RpMessage,CallbackCounter,0);
        NumberOfDrierLoaderCycles=0;
        //storeLoadArmParameters();
        LoadStages++;
        SetMotHome(HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM);  //set this point as the spool home

        ThreadLoadStateMachine(LoadStages);
        return OK;
    }
    uint32_t Thread_Load_Set_Load_Arm_To_Start_Position(void)
    {
        uint32_t numberOfSteps = 0;
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        if (LoadArmInfo.LoadArmRounds != 0xFF)
        {
            //Start Feeder Pid, Rotate Loading Arm Counter Thread Direction X Circles According To Rml. Feeder Speed Is 40
            numberOfSteps = MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulseperround*LoadArmInfo.LoadArmRounds*MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].microstep*MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulleyradius;
            Report("Thread_Load_Set_Load_Arm_To_Start_Position",__FILE__,__LINE__,numberOfSteps,RpMessage,NumberOfDrierLoaderCycles,0);
            NumberOfDrierLoaderCycles = LoadArmInfo.LoadArmRounds;
            status |= MotorMoveWithCallback(HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM, (1-MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].directionthreadwize),
                                            numberOfSteps, Thread_Load_Set_Load_Arm_To_Start_Position_Callback,1000);
        }
        else //number of circles is not known - compare to position of the motor to verify location at the stopper
        {
            Report("Thread_Load_Set_Load_Arm_To_Start_Position",__FILE__,__LINE__,LoadStages,RpMessage,NumberOfDrierLoaderCycles,0);
            status |= MotorMoveToStopper(HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM, (1-MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].directionthreadwize),
                                            MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulseperround/2, Thread_Load_Set_Load_Arm_To_Stopper_Callback,LoadArmInfo.LoadArmBackLash,1000);

        }
        //Use Notation How Many Rotations In The Drier, Or Check Against Stopper. Move Slowly
        return OK;
    }
    uint32_t Thread_Load_Jog_Feeder_To_Middle_Point_Callback(uint32_t deviceID, uint32_t BusyFlag)
    {
        CallbackCounter--;
        Report("Thread_Load_Jog_Feeder_To_Middle_Point_Callback",__FILE__,__LINE__,LoadStages,RpMessage,CallbackCounter,0);
        //storeLoadArmParameters();
        LoadStages++;
        ThreadLoadStateMachine(LoadStages);

        return OK;
    }

    uint32_t Thread_Load_HomingCallback(uint32_t MotorId, uint32_t ReadValue)
    {
        Report("Thread_Load_HomingCallback",__FILE__,__LINE__,LoadStages,RpMessage,CallbackCounter,0);
//        REPORT_MSG(MotorId, "Thread_Load_HomingCallback Motor Id");
        if (CallbackCounter)
        {
            CallbackCounter--;
            if (ReadValue != LIMIT)
            {
                //returned with a timeout
                TimeoutsCounter++;
            }
            if (CallbackCounter == 0)
            {
                if (TimeoutsCounter)
                {
                    LOG_ERROR(LoadStages,"Load sequence timeout");
                    TimeoutsCounter = 0;
                }
                else
                {
                    LoadStages++;
                    if (LoadStages == THREAD_LOAD_CLOSE_ROCKERS)
                    {
                        MotorSetMicroStep(HARDWARE_MOTOR_TYPE__MOTO_RLOADING,  keepmicrostep);
                        MotorSetMicroStep(HARDWARE_MOTOR_TYPE__MOTO_LLOADING, keepmicrostep);
                        MotorSetKvalRun(HARDWARE_MOTOR_TYPE__MOTO_RLOADING, keepkvalrun);
                        MotorSetKvalRun(HARDWARE_MOTOR_TYPE__MOTO_LLOADING, keepkvalrun);
                    }
                    if (LoadStages == THREAD_LOAD_CLOSE_DANCERS)
                    {
                        MotorSetKvalHold(HARDWARE_MOTOR_TYPE__MOTO_RDANCER, keepkvalhold);
                    }
                    if (LoadStages != THREAD_LOAD_INITIAL_TENSION) //on this stage we should wait for user call
                    {
                        ThreadLoadStateMachine(LoadStages);
                    }
                }
            }
        }
        else
            LOG_ERROR(MotorId, "Thread_Load_HomingCallback Callback is already 0");
        return OK;
    }
    uint32_t Thread_Load_Center_Head_Rockers(void)
    {
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        CallbackCounter++;
        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_DH_CLEANHEAD,1-MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DH_CLEANHEAD].directionthreadwize, 80,  Motor_Id_to_LS_IdUp[HARDWARE_MOTOR_TYPE__MOTO_DH_CLEANHEAD], Thread_Load_HomingCallback,10000);
        CallbackCounter++;
        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_DH_CLEANMECH,1-MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DH_CLEANMECH].directionthreadwize, 80,  Motor_Id_to_LS_IdUp[HARDWARE_MOTOR_TYPE__MOTO_DH_CLEANMECH], Thread_Load_HomingCallback,10000);
        return OK;
    }
    uint32_t Thread_Load_Open_Covers(void)
    {
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        //Open Dyeing Head Cover And Dryer Lid
        //HARDWARE_MOTOR_TYPE__MOTO_DH_LID = 2,
        //HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID = 4,
        //DeActivateHeadMagnet();
        CallbackCounter++;
        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_DH_LID,1-MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DH_LID].directionthreadwize, 200,  Motor_Id_to_LS_IdUp[HARDWARE_MOTOR_TYPE__MOTO_DH_LID], Thread_Load_HomingCallback,10000);
        CallbackCounter++;
        //MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID,1-MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID].directionthreadwize, 200,  Motor_Id_to_LS_IdUp[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID], Thread_Load_HomingCallback,10000);
        MotorGotoWithCallback(HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID, 0, Motor_Id_to_LS_IdUp[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID], Thread_Load_HomingCallback,4000);
        return OK;
    }
    uint32_t Thread_Load_Lift_Dancers(void)
    {
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        keepkvalhold = MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_RDANCER].kvalhold;
        MotorSetKvalHold(HARDWARE_MOTOR_TYPE__MOTO_RDANCER, 40);
        CallbackCounter++;
        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_RDANCER,1-MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_RDANCER].directionthreadwize, 15,  Motor_Id_to_LS_IdUp[HARDWARE_MOTOR_TYPE__MOTO_RDANCER], Thread_Load_HomingCallback,15000);
        CallbackCounter++;
        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_LDANCER1,1-MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_LDANCER1].directionthreadwize, 500,  Motor_Id_to_LS_IdUp[HARDWARE_MOTOR_TYPE__MOTO_LDANCER1], Thread_Load_HomingCallback,25000);

        return OK;
    }
    uint32_t Thread_Load_Lift_Rockers(void)
    //Machine Is Ready. Send Message, Start Timer To Close Lids, Wait For Operator Response
    {
        keepmicrostep = MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_RLOADING].microstep;
        keepkvalrun = MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_RLOADING].kvalrun;
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        MotorSetMicroStep(HARDWARE_MOTOR_TYPE__MOTO_RLOADING, 8);
        MotorSetMicroStep(HARDWARE_MOTOR_TYPE__MOTO_LLOADING, 8);
        MotorSetKvalRun(HARDWARE_MOTOR_TYPE__MOTO_RLOADING, 70);
        MotorSetKvalRun(HARDWARE_MOTOR_TYPE__MOTO_LLOADING, 70);
        Task_sleep(10);
        CallbackCounter++;
        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_RLOADING,1-MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_RLOADING].directionthreadwize, 250,  Motor_Id_to_LS_IdUp[HARDWARE_MOTOR_TYPE__MOTO_RLOADING], Thread_Load_HomingCallback,35000);
        CallbackCounter++;
        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_LLOADING,1-MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_LLOADING].directionthreadwize, 250,  Motor_Id_to_LS_IdUp[HARDWARE_MOTOR_TYPE__MOTO_LLOADING], Thread_Load_HomingCallback,35000);

        return OK;
    }
    uint32_t Thread_Load_Initial_Tension(void) //Check Spool Presence, run Winder Until Break Sensor Is Identifieing Movement For A Second
    {
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        if (FPGA_Read_limit_Switches(GPI_SW_SPOOL_EXISTS)==LIMIT)
        {
            REPORT_MSG(LIMIT, "No cone in winder");
            return ERROR;
        }
        CallbackCounter++;
        MotorMovetoBreakSensor (HARDWARE_MOTOR_TYPE__MOTO_WINDER,MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_WINDER].directionthreadwize, 500,  Thread_Load_HomingCallback,10000);

        return OK;

    }
    uint32_t Thread_Load_Close_Rockers(void)
    {
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        CallbackCounter++;
        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_RLOADING,MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_RLOADING].directionthreadwize, 250,  Motor_Id_to_LS_IdDown[HARDWARE_MOTOR_TYPE__MOTO_RLOADING], Thread_Load_HomingCallback,25000);
        CallbackCounter++;
        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_LLOADING,MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_LLOADING].directionthreadwize, 250,  Motor_Id_to_LS_IdDown[HARDWARE_MOTOR_TYPE__MOTO_LLOADING], Thread_Load_HomingCallback,25000);

        return OK;
    }

    uint32_t Thread_Load_Close_Dancers(void)
    //Send Dancer Motors To Preset Location, Check That The Dancers Are On The Thread
    {
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        CallbackCounter++;
        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_RDANCER,MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_RDANCER].directionthreadwize, 15,  Motor_Id_to_LS_IdDown[HARDWARE_MOTOR_TYPE__MOTO_RDANCER], Thread_Load_HomingCallback,4000);
        CallbackCounter++;
        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_LDANCER1,MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_LDANCER1].directionthreadwize, 500,  Motor_Id_to_LS_IdDown[HARDWARE_MOTOR_TYPE__MOTO_LDANCER1], Thread_Load_HomingCallback,10000);

        return OK;
    }
    uint32_t Thread_Load_Close_Lids(void)
    {
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        //Close Dyeing Head Cover And Dryer Lid
        //HARDWARE_MOTOR_TYPE__MOTO_DH_LID = 2,
        //HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID = 4,
        CallbackCounter++;
        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_DH_LID,MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DH_LID].directionthreadwize, 200,  Motor_Id_to_LS_IdDown[HARDWARE_MOTOR_TYPE__MOTO_DH_LID], Thread_Load_HomingCallback,10000);
        CallbackCounter++;
//        MotorMovetoLimitSwitch (HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID,MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID].directionthreadwize, 200,  Motor_Id_to_LS_IdDown[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID], Thread_Load_HomingCallback,10000);
        MotorGotoWithCallback(HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID, 2, Motor_Id_to_LS_IdDown[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID], Thread_Load_HomingCallback,4000);

        return OK;
    }
    uint32_t Thread_Load_Resume_Heating(void)
    {
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        ActivateHeadMagnet();

        if (HandleProcessParameters(&ProcessParametersRecover)!= OK)
        {
            LOG_ERROR (LoadStages, "Thread_Load_Resume_Heating failed");
        }
        else
        {
            Control_Dryer_Fan(START,75);//use START or STOP,  0 - 100%
            LoadStages++;
            ThreadLoadStateMachine(LoadStages);
        }
        return OK;
    }
    uint32_t Thread_Load_Jog_Feeder_To_Middle_Point(void)
    //Jog The Feeder Motor Until The Feeder Dancer Is At Middle Position
    {
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        CallbackCounter++;
        MotorMovetoDancerPosition (HARDWARE_MOTOR_TYPE__MOTO_RDRIVING,MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_RDRIVING].directionthreadwize, 100, FEEDER_DANCER ,true, Thread_Load_Jog_Feeder_To_Middle_Point_Callback,2000);
        return OK;
    }

    uint32_t Thread_Load_Dryer_MovetoEncoderPosition_Callback(uint32_t MotorId, uint32_t ReadValue)
    {
        Report("Thread_Load_Dryer_MovetoEncoderPosition_Callback",__FILE__,__LINE__,LoadStages,RpMessage,CallbackCounter,0);
        MotorSetMaxSpeed (HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM, 200);
        if(LoadingControlId != 0xFF)
        {
            MotorStop(ThreadMotorIdToMotorId[FEEDER_MOTOR],Hard_Hiz);
            RemoveControlCallback(LoadingControlId, ThreadLoadControlCBFunction );
            LoadingControlId = 0xFF;
        }
        if (CallbackCounter)
        {
            CallbackCounter--;
            if (CallbackCounter == 0)
            {
                LoadStages++;
                if (LoadStages != THREAD_LOAD_INITIAL_TENSION) //on this satge we should wait for user call
                {
                    ThreadLoadStateMachine(LoadStages);
                }
            }
        }
        else
            LOG_ERROR(MotorId, "Thread_Load_HomingCallback Callback is already 0");

        return OK;
    }
    uint32_t Thread_Load_Dryer_Loading_Callback(uint32_t MotorId, uint32_t ReadValue)
    {
        Report("Thread_Load_Dryer_Loading_Callback",__FILE__,__LINE__,LoadStages,RpMessage,NumberOfDrierLoaderCycles,0);
        Report("Thread_Load_Dryer_Loading_Callback details",__FILE__,__LINE__,MotorId,RpMessage,CallbackCounter,0);
        /*if(LoadingControlId != 0xFF)
        {
            MotorStop(ThreadMotorIdToMotorId[FEEDER_MOTOR],Hard_Hiz);
            RemoveControlCallback(LoadingControlId, ThreadLoadControlCBFunction );
            LoadingControlId = 0xFF;
        }*/
        MotorMovetoEncoderPosition(HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM,Thread_Load_Dryer_MovetoEncoderPosition_Callback,10000);
        return OK;
    }

    uint32_t Thread_Load_Dryer_Loading(void)
    {
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        LoadArmInfo.LoadArmRounds = (int)dryerbufferlength;
        if (LoadArmInfo.LoadArmRounds <= 2)
            LoadArmInfo.LoadArmRounds = 20;
        float numberOfSteps = 0;
        //Start Feeder Pid, Rotate Loading Arm Counter Thread Direction X Circles According To Rml. Feeder Speed Is 40
        SetOriginMotorSpeed(19);
//        OriginalMotorSpd_2PPS[FEEDER_MOTOR] = 1000;
//        CurrentControlledSpeed[FEEDER_MOTOR] = 1000;

        numberOfSteps = MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulseperround*LoadArmInfo.LoadArmRounds*MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].microstep*MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulleyradius;
        numberOfSteps -= 100;
        //numberOfSteps = MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulseperround*3.3*MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].microstep*MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulleyradius;
        Report("Thread Load State Machine step.",__FILE__,LoadStages,numberOfSteps,RpMessage,(int)(MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].microstep*MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulleyradius),0);
        MotorControlConfig[FEEDER_MOTOR].m_params.MAX = 1;
        MotorControlConfig[FEEDER_MOTOR].m_params.MIN = MotorsControl[FEEDER_MOTOR].outputproportionalpowerlimit*-1;
        MotorControlConfig[FEEDER_MOTOR].m_params.Kd = MotorsControl[FEEDER_MOTOR].derivativetime;
        MotorControlConfig[FEEDER_MOTOR].m_params.Kp = MotorsControl[FEEDER_MOTOR].proportionalgain;
        MotorControlConfig[FEEDER_MOTOR].m_params.Ki = MotorsControl[FEEDER_MOTOR].integraltime;
        MotorControlConfig[FEEDER_MOTOR].m_params.IntegralErrorMultiplier = MotorsControl[FEEDER_MOTOR].setpointramprateorsoftstartramp;
        MotorControlConfig[FEEDER_MOTOR].m_params.ProportionalErrorMultiplier = MotorsControl[FEEDER_MOTOR].outputonoffhysteresisvalue;
        MotorControlConfig[FEEDER_MOTOR].m_params.epsilon = MotorsControl[FEEDER_MOTOR].epsilon;
        MotorControlConfig[FEEDER_MOTOR].m_params.dt = MotorsControl[FEEDER_MOTOR].controloutputtype;
        MotorControlConfig[FEEDER_MOTOR].m_ingnoreValue =  MotorsControl[FEEDER_MOTOR].sensorcorrectionadjustment; // the minimal change required to change the motor speed in pulses
        MotorControlConfig[FEEDER_MOTOR].m_calculatedError = 0;
        MotorControlConfig[FEEDER_MOTOR].m_integral = 0;
        MotorControlConfig[FEEDER_MOTOR].m_isEnabled = true;
        MotorControlConfig[FEEDER_MOTOR].m_isReady = true;
        MotorControlConfig[FEEDER_MOTOR].m_mesuredParam = 0;
        MotorControlConfig[FEEDER_MOTOR].m_preError = 0;
        MotorControlConfig[FEEDER_MOTOR].m_SetParam = 0;//need to update SetParams on presegment stage
        MotorSetDirection(HARDWARE_MOTOR_TYPE__MOTO_RDRIVING,MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_RDRIVING].directionthreadwize);

        MotorSetMaxSpeed (HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM, MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulseperround/4);

        LoadingControlId = AddControlCallback(ThreadLoadControlCBFunction, eOneMillisecond,Control_Read_Dancer_Position,(IfTypeThread*0x100+FEEDER_MOTOR),FEEDER_DANCER,FEEDER_MOTOR);
        Report("AddControlCallback feeder",__FILE__,__LINE__,LoadingControlId,RpMessage,IfTypeThread*0x100+FEEDER_MOTOR,0);
        CallbackCounter++;
        Report("Thread_Load_Dryer_Loading",__FILE__,__LINE__,LoadStages,RpMessage,CallbackCounter,0);
        MotorMoveWithCallback (HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM, MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].directionthreadwize,
                               numberOfSteps,    Thread_Load_Dryer_Loading_Callback, 100000);

        //Keep Notation How Many Rotations In The Dryer
        //LoadArmInfo.LoadArmBackLash = 0;
        LoadArmInfo.LoadArmRounds = (int)dryerbufferlength;
        //FileWrite(&LoadArmInfo, sizeof(LoadArmInfo),LoadArmPath,BIOS_WAIT_FOREVER);
        return OK;
    }
    uint32_t Thread_Load_Jog_ThreadStop(uint32_t index, uint32_t ReadValue)
    {
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        SafeRemoveControlCallback(LoadingControlId, Thread_Load_Jog_ThreadStop );
        LoadingControlId = 0xFF;
        ThreadAbortJoggingFunc();
        LoadStages++;
        ThreadLoadStateMachine(LoadStages);
        return OK;
    }
    uint32_t Thread_Load_Jog_Thread(void)
    //Jog Thread Shortly To Make Sure Spool Is Running. Report End Of Loading
    {
        REPORT_MSG(LoadStages, "Thread Load State Machine step");
        ThreadJoggingFunc(20);
        LoadingControlId = AddControlCallback(Thread_Load_Jog_ThreadStop, eOneSecond*5,Control_Read_Dancer_Position,(IfTypeThread*0x100+FEEDER_MOTOR),FEEDER_DANCER,FEEDER_MOTOR);
        return OK;
    }
    uint32_t Thread_Load_End(void)
    {
        REPORT_MSG(LoadStages,"Loading Ended");
        if(LoadingControlId != 0xFF)
        {
            MotorStop(ThreadMotorIdToMotorId[FEEDER_MOTOR],Hard_Hiz);
            RemoveControlCallback(LoadingControlId, ThreadLoadControlCBFunction );
            LoadingControlId = 0xFF;
        }
        if(PullerControlId != 0xFF)
        {
            MotorStop(ThreadMotorIdToMotorId[POOLER_MOTOR],Hard_Hiz);
            RemoveControlCallback(PullerControlId, ThreadLoadControlCBFunction );
            PullerControlId = 0xFF;
        }
        if(WinderControlId != 0xFF)
        {
            MotorStop(ThreadMotorIdToMotorId[WINDER_MOTOR],Hard_Hiz);
            RemoveControlCallback(WinderControlId, ThreadLoadControlCBFunction );
            WinderControlId = 0xFF;
        }

        MotorStopAction(HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM);
        MotorStopAction(HARDWARE_MOTOR_TYPE__MOTO_RLOADING);
        MotorStopAction(HARDWARE_MOTOR_TYPE__MOTO_LLOADING);
        MotorStopAction(HARDWARE_MOTOR_TYPE__MOTO_RDANCER);
        MotorStopAction(HARDWARE_MOTOR_TYPE__MOTO_LDANCER1);
        MotorStopAction(HARDWARE_MOTOR_TYPE__MOTO_DRYER_LID);
        MotorStopAction(HARDWARE_MOTOR_TYPE__MOTO_DH_LID);
        MotorStop(HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM,Hard_Stop);
        LoadStages = THREAD_LOAD_INIT;
        return OK;
    }
    uint32_t Thread_Load_Dryer_UnLoading(void)
    {
        REPORT_MSG(LoadStages, "Thread UnLoad State Machine step");
        LoadArmInfo.LoadArmRounds = 0;
        uint32_t numberOfSteps = 0;
        //Start Feeder Pid, Rotate Loading Arm Counter Thread Direction X Circles According To Rml. Feeder Speed Is 40
        SetOriginMotorSpeed(19);
//        OriginalMotorSpd_2PPS[FEEDER_MOTOR] = 1000;
//        CurrentControlledSpeed[FEEDER_MOTOR] = 1000;

        numberOfSteps = MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulseperround*LoadArmInfo.LoadArmRounds*MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].microstep*MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulleyradius;
        MotorControlConfig[POOLER_MOTOR].m_params.MAX = 1;
        MotorControlConfig[POOLER_MOTOR].m_params.MIN = MotorsControl[POOLER_MOTOR].outputproportionalpowerlimit*-1;
        MotorControlConfig[POOLER_MOTOR].m_params.Kd = MotorsControl[POOLER_MOTOR].derivativetime;
        MotorControlConfig[POOLER_MOTOR].m_params.Kp = MotorsControl[POOLER_MOTOR].proportionalgain;
        MotorControlConfig[POOLER_MOTOR].m_params.Ki = 0;//MotorsControl[POOLER_MOTOR].integraltime;
        MotorControlConfig[POOLER_MOTOR].m_params.IntegralErrorMultiplier = MotorsControl[POOLER_MOTOR].setpointramprateorsoftstartramp;
        MotorControlConfig[POOLER_MOTOR].m_params.ProportionalErrorMultiplier = MotorsControl[POOLER_MOTOR].outputonoffhysteresisvalue;
        MotorControlConfig[POOLER_MOTOR].m_params.epsilon = MotorsControl[POOLER_MOTOR].epsilon;
        MotorControlConfig[POOLER_MOTOR].m_params.dt = MotorsControl[POOLER_MOTOR].controloutputtype;
        MotorControlConfig[POOLER_MOTOR].m_ingnoreValue =  MotorsControl[POOLER_MOTOR].sensorcorrectionadjustment; // the minimal change required to change the motor speed in pulses
        MotorControlConfig[POOLER_MOTOR].m_calculatedError = 0;
        MotorControlConfig[POOLER_MOTOR].m_integral = 0;
        MotorControlConfig[POOLER_MOTOR].m_isEnabled = true;
        MotorControlConfig[POOLER_MOTOR].m_isReady = true;
        MotorControlConfig[POOLER_MOTOR].m_mesuredParam = 0;
        MotorControlConfig[POOLER_MOTOR].m_preError = 0;
        MotorControlConfig[POOLER_MOTOR].m_SetParam = 0;//need to update SetParams on presegment stage
        MotorSetDirection(HARDWARE_MOTOR_TYPE__MOTO_LDRIVING,MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_LDRIVING].directionthreadwize);

        PullerControlId = AddControlCallback(ThreadLoadControlCBFunction, eOneMillisecond,Control_Read_Dancer_Position,(IfTypeThread*0x100+POOLER_MOTOR),POOLER_DANCER,POOLER_MOTOR);
        Report("AddControlCallback Puller",__FILE__,__LINE__,PullerControlId,RpMessage,IfTypeThread*0x100+POOLER_MOTOR,0);
////////////////////////
        MotorControlConfig[WINDER_MOTOR].m_params.MAX = 1;
        MotorControlConfig[WINDER_MOTOR].m_params.MIN = MotorsControl[WINDER_MOTOR].outputproportionalpowerlimit*-1;
        MotorControlConfig[WINDER_MOTOR].m_params.Kd = MotorsControl[WINDER_MOTOR].derivativetime;
        MotorControlConfig[WINDER_MOTOR].m_params.Kp = MotorsControl[WINDER_MOTOR].proportionalgain;
        MotorControlConfig[WINDER_MOTOR].m_params.Ki = 0;//MotorsControl[WINDER_MOTOR].integraltime;
        MotorControlConfig[WINDER_MOTOR].m_params.IntegralErrorMultiplier = MotorsControl[WINDER_MOTOR].setpointramprateorsoftstartramp;
        MotorControlConfig[WINDER_MOTOR].m_params.ProportionalErrorMultiplier = MotorsControl[WINDER_MOTOR].outputonoffhysteresisvalue;
        MotorControlConfig[WINDER_MOTOR].m_params.epsilon = MotorsControl[WINDER_MOTOR].epsilon;
        MotorControlConfig[WINDER_MOTOR].m_params.dt = MotorsControl[WINDER_MOTOR].controloutputtype;
        MotorControlConfig[WINDER_MOTOR].m_ingnoreValue =  MotorsControl[WINDER_MOTOR].sensorcorrectionadjustment; // the minimal change required to change the motor speed in pulses
        MotorControlConfig[WINDER_MOTOR].m_calculatedError = 0;
        MotorControlConfig[WINDER_MOTOR].m_integral = 0;
        MotorControlConfig[WINDER_MOTOR].m_isEnabled = true;
        MotorControlConfig[WINDER_MOTOR].m_isReady = true;
        MotorControlConfig[WINDER_MOTOR].m_mesuredParam = 0;
        MotorControlConfig[WINDER_MOTOR].m_preError = 0;
        MotorControlConfig[WINDER_MOTOR].m_SetParam = 0;//need to update SetParams on presegment stage
        MotorSetDirection(HARDWARE_MOTOR_TYPE__MOTO_WINDER,MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_WINDER].directionthreadwize);

        WinderControlId = AddControlCallback(ThreadLoadControlCBFunction, eOneMillisecond,Control_Read_Dancer_Position,(IfTypeThread*0x100+WINDER_MOTOR),WINDER_DANCER,WINDER_MOTOR);
        Report("AddControlCallback Winder",__FILE__,__LINE__,WinderControlId,RpMessage,IfTypeThread*0x100+WINDER_MOTOR,0);

////////////////////////
        MotorSetDirection(HARDWARE_MOTOR_TYPE__MOTO_DRYER_DRIVING,MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_DRIVING].directionthreadwize);
        MotorSetSpeed(HARDWARE_MOTOR_TYPE__MOTO_DRYER_DRIVING, OriginalMotorSpd_2PPS[DRYER_MOTOR]);

        CallbackCounter++;
        //MotorMoveWithCallback (HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM, MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].directionthreadwize,
        //                       numberOfSteps,    Thread_Load_Dryer_Loading_Callback, 100000);
        Report("Thread_Load_Set_Load_Arm_To_Start_Position",__FILE__,__LINE__,LoadStages,RpMessage,NumberOfDrierLoaderCycles,0);
        LoadArmInfo.LoadArmBackLash = 5;

        status |= MotorMoveToStopper(HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM, (1-MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].directionthreadwize),
                                        MotorsCfg[HARDWARE_MOTOR_TYPE__MOTO_DRYER_LOADARM].pulseperround/4, Thread_Load_Set_Load_Arm_To_Stopper_Callback,LoadArmInfo.LoadArmBackLash,1000);

        //Keep Notation How Many Rotations In The Dryer
        //LoadArmInfo.LoadArmBackLash = 0;
        LoadArmInfo.LoadArmRounds = (int)dryerbufferlength;
        FileWrite(&LoadArmInfo, sizeof(LoadArmInfo),LoadArmPath,BIOS_WAIT_FOREVER);
        return OK;
    }

    uint32_t ThreadLoadStateMachine( THREAD_LOAD_STAGES_ENUM ReadValue)
    {
        REPORT_MSG(ReadValue,"ThreadLoadStateMachine");
        if (LoadStages!=ReadValue)
            LoadStages = ReadValue;
        switch (ReadValue)
        {
        case THREAD_LOAD_INIT:
            //LoadStages++;
            Thread_Load_Init();
            break;
        case THREAD_LOAD_REDUCE_HEAT:  //HEATERS OFF, DRYER BLOWER OFF, BLOWER LOW,
            //LoadStages++;
            Thread_Load_Reduce_Heat();
            break;
        case THREAD_LOAD_SET_LOAD_ARM_TO_START_POSITION://USE NOTATION HOW MANY ROTATIONS IN THE DRYER, OR CHECK AGAINS STOPPER. MOVE SLOWLY
            //LoadStages++;
            //Thread_Load_Set_Load_Arm_To_Start_Position();
            Thread_Load_Dryer_UnLoading();
            break;
        case THREAD_LOAD_CENTER_HEAD_ROCKERS:
            //LoadStages++;
            Thread_Load_Center_Head_Rockers();
            break;
        case THREAD_LOAD_OPEN_COVERS:  //OPEN DYEING HEAD COVER AND DRYER LID
            //LoadStages++;
            Thread_Load_Open_Covers();
            break;
        case THREAD_LOAD_LIFT_DANCERS:
            //LoadStages++;
            Thread_Load_Lift_Dancers();
            break;
        case THREAD_LOAD_LIFT_ROCKERS: //MACHINE IS READY. SEND MESSAGE, START TIMER TO CLOSE LIDS, WAIT FOR OPERATOR RESPONSE
            //LoadStages++;
            Thread_Load_Lift_Rockers();
            break;
        case THREAD_LOAD_INITIAL_TENSION://CHECK SPOOL PRESENCERUN WINDER UNTIL BREAK SENSOR IS IDENTIFIEING MOVEMENT FOR A SECOND
            //LoadStages++;
            Thread_Load_Initial_Tension();
            break;
        case THREAD_LOAD_CLOSE_ROCKERS:
            //LoadStages++;
            Thread_Load_Close_Rockers();
            break;
        case THREAD_LOAD_CLOSE_DANCERS: //SEND DANCER MOTORS TO PRESET LOCATION, CHECK THAT THE DANCERS ARE ON THE THREAD
            //LoadStages++;
            Thread_Load_Close_Dancers();
            break;
        case THREAD_LOAD_CLOSE_LIDS:
            //LoadStages++;
            Thread_Load_Close_Lids();
            break;
        case THREAD_LOAD_JOG_FEEDER_TO_MIDDLE_POINT://JOG THE FEEDER MOTOR UNTIL THE FEEDER DANCER IS AT MIDDLE POSITION
            //LoadStages++;
            Thread_Load_Jog_Feeder_To_Middle_Point();
            break;
        case THREAD_LOAD_DRYER_LOADING: //START FEEDER PID, ROTATE LOADING ARM COUNTER THREAD DIRECTION X CIRCLES ACCORDING TO RML. FEEDER SPEED IS 40
                                    //KEEP NOTATION HOW MANY ROTATIONS IN THE DRYER
            //LoadStages++;
            Thread_Load_Dryer_Loading();
            break;
        case THREAD_LOAD_RESUME_HEATING:
            //LoadStages++;
            Thread_Load_Resume_Heating();
            break;
        case THREAD_LOAD_JOG_THREAD: //JOG THREAD SHORTLY TO MAKE SURE SPOOL IS RUNNING. REPORT END OF LOADING
            //LoadStages++;
            Thread_Load_Jog_Thread();
            break;
        case THREAD_LOAD_END:
            LoadStages = THREAD_LOAD_END;
            Thread_Load_End();
            break;
        default:
            LOG_ERROR(LoadStages,"ERROR IN LOAD STATE MACHINE");
            break;
    }
    return OK;
}
uint32_t ThreadLoadButton(THREAD_LOAD_STAGES_ENUM ReadValue)
{
    Report("ThreadLoadButton",__FILE__,__LINE__,LoadStages,RpMessage,ReadValue,0);
    if (LoadStages > ReadValue)
    {
        ThreadLoadStateMachine(LoadStages+1);
    }
    else
    {
        ThreadLoadStateMachine(ReadValue);
    }
    return OK;
}
uint32_t LoadCounter = 0;

uint32_t ThreadLoadControlCBFunction(uint32_t IfIndex, uint32_t ReadValue)
{
    //read value is the dancer angle
    int i;
    int DancerId;
    int32_t TranslatedReadValue, avreageSampleValue = 0;
    int index=MAX_THREAD_MOTORS_NUM;
    //double tempcalcspeed = 0;
    uint32_t calculated_speed;
    double NormalizedError;

    if (IfIndex>>8 != IfTypeThread)
    {
        LOG_ERROR (IfIndex, "Wrong  Interface type");
        return 0xFFFFFFFF;
    }
    index = IfIndex&0xFF;

    DancerId = ThreadMotorIdToDancerId[index];
    if (ReadValue < 10)
    {
        Report("Dancer value read too small.",__FILE__,__LINE__,DancerId,RpError,ReadValue,0);
        return OK;
    }
    if (ReadValue == 0x3FFF)
    {
        return OK;
    }
    TranslatedReadValue = ReadValue - DancersCfg[DancerId].zeropoint;
    if (index == POOLER_MOTOR)
    {
        //pooler dancer is right sided: data is opposite
        TranslatedReadValue = (-1*TranslatedReadValue);
    }
    //TranslatedReadValue = 0;//test
    MotorSamples[index][MotorSamplePointer[index]] = TranslatedReadValue;//(-1 * TranslatedReadValue);
    MotorSamplePointer[index]++;
    if (MotorSamplePointer[index] >= MotorsControl[index].pvinputfilterfactormode)
        MotorSamplePointer[index] = 0;
    for (i=0;i<MotorsControl[index].pvinputfilterfactormode;i++)
        avreageSampleValue += MotorSamples[index][i];
    avreageSampleValue = avreageSampleValue / MotorsControl[index].pvinputfilterfactormode;


    NormalizedError = avreageSampleValue*NormalizedErrorCoEfficient[index];
    MotorControlConfig[index].m_mesuredParam = NormalizedError;
    MotorControlConfig[index].m_calculatedError = AdvancedPIDAlgorithmCalculation((float)MotorControlConfig[index].m_SetParam , (float)MotorControlConfig[index].m_mesuredParam,
                                                                          &MotorControlConfig[index].m_params,   &MotorControlConfig[index].m_preError, &MotorControlConfig[index].m_integral);
    if (index != FEEDER_MOTOR) //feeder unit handles errors opposite to left unit
    {
        MotorControlConfig[index].m_calculatedError = (-1*MotorControlConfig[index].m_calculatedError);
    }
    calculated_speed = (1-MotorControlConfig[index].m_calculatedError)*OriginalMotorSpd_2PPS[index];
    if (fabs(calculated_speed-CurrentControlledSpeed[index])> MotorControlConfig[index].m_ingnoreValue)
    {
        CurrentControlledSpeed[index] = calculated_speed;
        MotorSetSpeed(ThreadMotorIdToMotorId[index], calculated_speed);
    }
/*    LoadCounter++;
    if ((LoadCounter % 5001) == 0)
    {
          Report("MotorSpeedUpdated",__FILE__,index,abs(TranslatedReadValue),RpWarning,(int)CurrentControlledSpeed[index],0);
    }*/
 return OK;
}
void ThreadLoadRequest(MessageContainer* requestContainer)
{
//#ifdef DEBUG_TEST_FUNCTIONS
    MessageContainer responseContainer;
    uint8_t* container_buffer;
    //uint32_t status = OK;

    StubHeatingTestRequest* request = stub_heating_test_request__unpack(NULL, requestContainer->data.len, requestContainer->data.data);
    StubHeatingTestResponse response = STUB_HEATING_TEST_RESPONSE__INIT;

    responseContainer = createContainer(MESSAGE_TYPE__StubHeatingTestResponse, requestContainer->token, false, &response, &stub_heating_test_response__pack, &stub_heating_test_response__get_packed_size);
    container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));


    int LoadStage = (int)request->dryerzone1temp;
    LoadStages = LoadStage;
    ThreadLoadStateMachine(LoadStage);

    /*if (status)
    {
        responseContainer.has_error = true;
        responseContainer.error = ERROR_CODE__JOB_UNSPECIFIED_ERROR;
    }*/
    size_t container_size = message_container__pack(&responseContainer, container_buffer);
    my_free(responseContainer.data.data);
    //USBCDCD_sendData(container_buffer, container_size,10);
    SendChars(container_buffer, container_size);
    stub_heating_test_request__free_unpacked(request,NULL);

//#else
//    LOG_ERROR (-1, "Heating Control not on debug");
//    return ERROR;
//#endif
}
void ThreadLoadPollRequest(MessageContainer* requestContainer)
{
    uint8_t* container_buffer;

    StubHeatingTestPollRequest* request = stub_heating_test_poll_request__unpack(NULL, requestContainer->data.len, requestContainer->data.data);

    StubHeatingTestPollResponse response = STUB_HEATING_TEST_POLL_RESPONSE__INIT;
    MessageContainer responseContainer;

    response.has_heater1percentage = true;
    response.heater1percentage = LoadStages;
    responseContainer = createContainer(MESSAGE_TYPE__StubHeatingTestPollResponse, requestContainer->token, false, &response, &stub_heating_test_poll_response__pack, &stub_heating_test_poll_response__get_packed_size);
    container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));


/*
    {
        responseContainer.has_error = true;
        responseContainer.error = ERROR_CODE__JOB_UNSPECIFIED_ERROR;
    }*/
    size_t container_size = message_container__pack(&responseContainer, container_buffer);
    my_free(responseContainer.data.data);
    SendChars(container_buffer, container_size);
    stub_heating_test_poll_request__free_unpacked(request,NULL);
}