aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Embedded_SW/Embedded/Modules/IDS/IDS_maint.c
blob: a160a0d6a25bf428983ba2c384da9e57abf7dd73 (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<
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.Integration.Operation;
using Tango.Integration.Upgrade;

namespace Tango.MachineStudio.Common.FirmwareUpgrade
{
    /// <summary>
    /// Firmware Upgrade Manager.
    /// </summary>
    public interface IFirmwareUpgrader
    {
        /// <summary>
        /// Performs a firmware upgrade.
        /// </summary>
        /// <param name="tfpStream">The TFP stream.</param>
        Task<FirmwareUpgradeHandler> PerformUpgrade(Stream tfpStream);

        /// <summary>
        /// Invokes the upgrade dialog.
        /// </summary>
        void InvokeUpgradeUI();
    }
}
/a> 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
/************************************************************************************************************************
 * Ids_maint.c
 * Printing module is responsible for :
 * operating the dispensers according to predefined dispensing rate from the UI
 **************************************************************************************************************************/
#include "include.h"
#include "ids.h"
#include "ids_ex.h"
#include "../control/control.h"
#include "../control/pidalgo.h"
#include "../thread/thread.h"
#include "PMR/Hardware/Hardwaremotor.pb-c.h"
#include "PMR/Hardware/HardwareDispenser.pb-c.h"
#include "StateMachines/Printing/printingSTM.h"

#include "drivers/I2C_Communication/ADC_MUX/ADC_MUX.h"
#include "drivers/I2C_Communication/Dispenser_Card/IO_Ports/Dispenser_IO.h"

#include "drivers/FPGA/FPGA_GPIO/FPGA_GPIO.h"
#include "drivers/FPGA/FPGA_SPI_Comm.h"
#include "drivers/Motors/Motor.h"
#include "drivers/Valves/Valve.h"


FPGA_GPI_ENUM     Dispenser_Id_to_LS_Id[MAX_SYSTEM_DISPENSERS] = {
      GPI_LS_DISPENSER_DOWN_1, //MOTO_DISPENSER_1 = 6,
      GPI_LS_DISPENSER_DOWN_2, //MOTO_DISPENSER_2 = 7,
      GPI_LS_DISPENSER_DOWN_3, //MOTO_DISPENSER_3 = 8,
      GPI_LS_DISPENSER_DOWN_4, //MOTO_DISPENSER_4 = 9,
      GPI_LS_DISPENSER_DOWN_5, //MOTO_DISPENSER_5 = 10,
      GPI_LS_DISPENSER_DOWN_6, //MOTO_DISPENSER_6 = 11,
      GPI_LS_DISPENSER_DOWN_7, //MOTO_DISPENSER_7 = 12,
      GPI_LS_DISPENSER_DOWN_8, //MOTO_DISPENSER_8 = 13,
};
FPGA_GPI_ENUM     Dispenser_Id_to_LS_Empty_Id[MAX_SYSTEM_DISPENSERS] = {
      GPI_LS_DISPENSER_UP_1, //MOTO_DISPENSER_1 = 6,
      GPI_LS_DISPENSER_UP_2, //MOTO_DISPENSER_2 = 7,
      GPI_LS_DISPENSER_UP_3, //MOTO_DISPENSER_3 = 8,
      GPI_LS_DISPENSER_UP_4, //MOTO_DISPENSER_4 = 9,
      GPI_LS_DISPENSER_UP_5, //MOTO_DISPENSER_5 = 10,
      GPI_LS_DISPENSER_UP_6, //MOTO_DISPENSER_6 = 11,
      GPI_LS_DISPENSER_UP_7, //MOTO_DISPENSER_7 = 12,
      GPI_LS_DISPENSER_UP_8, //MOTO_DISPENSER_8 = 13,
};
FPGA_GPI_ENUM     Dispenser_Id_to_Alarm_LS_Id[MAX_SYSTEM_DISPENSERS*2] = {
      GPI_LS_DISPENSER_UP_1, //MOTO_DISPENSER_1 = 6,
      GPI_LS_DISPENSER_UP_2, //MOTO_DISPENSER_2 = 7,
      GPI_LS_DISPENSER_UP_3, //MOTO_DISPENSER_3 = 8,
      GPI_LS_DISPENSER_UP_4, //MOTO_DISPENSER_4 = 9,
      GPI_LS_DISPENSER_UP_5, //MOTO_DISPENSER_5 = 10,
      GPI_LS_DISPENSER_UP_6, //MOTO_DISPENSER_6 = 11,
      GPI_LS_DISPENSER_UP_7, //MOTO_DISPENSER_7 = 12,
      GPI_LS_DISPENSER_UP_8, //MOTO_DISPENSER_8 = 13,
      GPI_LS_DISPENSER_25_1, //MOTO_DISPENSER_1 = 6,
      GPI_LS_DISPENSER_25_2, //MOTO_DISPENSER_2 = 7,
      GPI_LS_DISPENSER_25_3, //MOTO_DISPENSER_3 = 8,
      GPI_LS_DISPENSER_25_4, //MOTO_DISPENSER_4 = 9,
      GPI_LS_DISPENSER_25_5, //MOTO_DISPENSER_5 = 10,
      GPI_LS_DISPENSER_25_6, //MOTO_DISPENSER_6 = 11,
      GPI_LS_DISPENSER_25_7, //MOTO_DISPENSER_7 = 12,
      GPI_LS_DISPENSER_25_8, //MOTO_DISPENSER_8 = 13,
};
callback_fptr HomingRequestCallback[MAX_SYSTEM_DISPENSERS]={0,0,0,0,0,0,0,0};
callback_fptr HomingBacklashCallback[MAX_SYSTEM_DISPENSERS]={0,0,0,0,0,0,0,0};
uint32_t HomingBacklashTimeout[MAX_SYSTEM_DISPENSERS];
uint32_t HomingBacklashTime[MAX_SYSTEM_DISPENSERS];

int32_t KeepMicrostep[MAX_SYSTEM_DISPENSERS];

bool HomingActive[MAX_SYSTEM_DISPENSERS] = {false,false,false,false,false,false,false,false};
bool PrimingActive[MAX_SYSTEM_DISPENSERS] = {false,false,false,false,false,false,false,false};
uint32_t DispenserHomingControlId[MAX_SYSTEM_DISPENSERS] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint32_t DispenserBacklashControlId[MAX_SYSTEM_DISPENSERS] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint32_t DispenserHomingTime[MAX_SYSTEM_DISPENSERS] = {0,0,0,0,0,0,0,0};
#define INITIAL_DISPENSER_PRESSURE 2.10
#define INITIAL_DISPENSER_TIMEOUT_LIMIT 60000
#define INITIAL_DISPENSER_TIMEOUT 100
#define INITIAL_DISPENSER_SPEED 1000

double   InitialDispenserPressure = INITIAL_DISPENSER_PRESSURE;
uint32_t InitialDispenserTimeout = INITIAL_DISPENSER_TIMEOUT_LIMIT;
uint32_t InitialDispenserTimeLag = INITIAL_DISPENSER_TIMEOUT;
uint32_t InitialDispenserSpeed = INITIAL_DISPENSER_SPEED;

uint32_t IDS_StopHomeDispenserBuildPressure (uint32_t deviceID);

AutoHoming_Config_enum AutoHoming_Config = AutoHoming_off;
void IDS_Dispenser_SetAutoHoming_Config(AutoHoming_Config_enum Config)
{
    Report("IDS_Dispenser_SetAutoHoming_Config ",__FILE__,__LINE__,Config,RpWarning,AutoHoming_Config,0);
    AutoHoming_Config = Config;
}

void IDS_Dispenser_SetBackLashValues(double   initialdispenserpressure,   uint32_t initialdispensertimeout,   uint32_t initialdispensertimelag,   uint32_t initialdispenserspeed)
{
    InitialDispenserPressure = initialdispenserpressure;
    InitialDispenserTimeout = initialdispensertimeout;
    InitialDispenserTimeLag = initialdispensertimelag;
    InitialDispenserSpeed = INITIAL_DISPENSER_SPEED;

    Report("IDS_Dispenser_SetBackLashValues ",__FILE__,InitialDispenserPressure,InitialDispenserTimeout,RpWarning,(int)InitialDispenserTimeLag,0);
}
uint32_t IDS_HomeDispenserWaitForHomingEndCallback(uint32_t DispenserId, uint32_t ReadValue)
{
    HomingBacklashTime[DispenserId]+=eOneSecond;
    if (( HomingActive[DispenserId]== false) ||((HomingBacklashTime[DispenserId]>=HomingBacklashTimeout[DispenserId])&&(HomingBacklashTimeout[DispenserId]>0)))
       {
           //stop this control loop
           SafeRemoveControlCallback(DispenserBacklashControlId[DispenserId], IDS_HomeDispenserWaitForHomingEndCallback );
           DispenserBacklashControlId[DispenserId] = 0xFF;

           if (HomingBacklashCallback[DispenserId])
           {
               if ( HomingActive[DispenserId]== false)
                   HomingBacklashCallback[DispenserId](DispenserId,OK);
               else
                   HomingBacklashCallback[DispenserId](DispenserId,ERROR);
           }
           HomingBacklashCallback[DispenserId] = 0;
       }
    return OK;
}
uint32_t IDS_HomeDispenserWaitForHomingEnd(uint32_t DispenserId,  uint32_t timeout , callback_fptr callback)
{
    assert(DispenserId < MAX_SYSTEM_DISPENSERS);

    if (HomingBacklashCallback[DispenserId]!=NULL)
        return ERROR;
    HomingBacklashCallback[DispenserId] = callback;
    HomingBacklashTimeout[DispenserId] = timeout;
    HomingBacklashTime[DispenserId] = 0;

    if (DispenserBacklashControlId[DispenserId] != 0xFF)
    {
        RemoveControlCallback(DispenserBacklashControlId[DispenserId], IDS_HomeDispenserWaitForHomingEndCallback );
        DispenserBacklashControlId[DispenserId] = 0xFF;
        //return ERROR;
    }
    DispenserBacklashControlId[DispenserId] = AddControlCallback( IDS_HomeDispenserWaitForHomingEnd,eOneSecond , TemplateDataReadCBFunction,DispenserId,0, 0 );
    if ( DispenserBacklashControlId[DispenserId] == 0xFF)
        return ERROR;

    return OK;
}

uint32_t IDS_HomeDispenserBackMoveCallback(uint32_t motorId, uint32_t ReadValue)
{
    uint8_t DispenserId = motorId-HARDWARE_MOTOR_TYPE__MOTO_DISPENSER_1;
    if ((GetDispenserPressure(DispenserId)>=InitialDispenserPressure)||(DispenserHomingTime[DispenserId]>InitialDispenserTimeout))
    {
        MotorStop(motorId,Hard_Hiz);
        CurrentDispenserSpeed[DispenserId] = 0;
        if (Extended_Motor_Param == true)
            Power_Step_01_Dispenser_Mode(DispenserId,Voltage);
        MotorSetMicroStep(motorId, KeepMicrostep[DispenserId]);
        HomingActive[DispenserId]= false;
        PrimingActive[DispenserId]= false;
        Control_TCA9534ByPass(DispenserId,DISABLE);// use ENABLE or DISABLE

        //close dry air valve in the dispenser
        Valve_Set(IDS_Id_to_AirValve[DispenserId], Atm_MidTank_OFF);
        Disable_MidTank_Pressure_Reading(DispenserId);

        Report("End backlash",__FILE__,millisecondCounter,(int)DispenserId,RpWarning,(int)DispenserHomingTime[DispenserId],0);
        if (SafeRemoveControlCallback(DispenserHomingControlId[DispenserId], IDS_HomeDispenserBackMoveCallback )==OK)
            DispenserHomingControlId[DispenserId] = 0xFF;
        else
            Report("Remove control callback failed",__FILE__,__LINE__,(int)DispenserId,RpWarning,(int)DispenserHomingControlId[DispenserId],0);
        DispenserHomingTime[DispenserId]=0;
    }
    else
    {
        DispenserHomingTime[DispenserId]+=InitialDispenserTimeLag;
    }
    return OK;
}
uint32_t IDS_HomeDispenserCallback(uint32_t motorId, uint32_t ReadValue)
{
    uint8_t DispenserId = motorId-HARDWARE_MOTOR_TYPE__MOTO_DISPENSER_1;

    Read_MidTank_Pressure_Sensor(DispenserId);
    //close dry air valve in the dispenser
    //Valve_Set(IDS_Id_to_AirValve[DispenserId], Atm_MidTank_OFF);
    //Disable_MidTank_Pressure_Reading(DispenserId);
    //    MotorSetMicroStep(motorId, KeepMicrostep[DispenserId]);
    if (HomingRequestCallback[DispenserId])
    {
        HomingRequestCallback[DispenserId](DispenserId,0);
        HomingRequestCallback[DispenserId] = NULL;
    }
//    HomingActive[DispenserId]= false;
    IDS_Dispenser_RefillEnded ( DispenserId, MotorsCfg[motorId].microstep);
    Report("Start backlash",__FILE__,millisecondCounter,(int)DispenserId,RpWarning,(int)DispenserHomingTime[DispenserId],0);
    DispenserHomingControlId[DispenserId] = AddControlCallback( IDS_HomeDispenserBackMoveCallback, InitialDispenserTimeLag, GetDispenserPressure,motorId, motorId, 0 );
    MotorSetDirection(motorId,MotorsCfg[motorId].directionthreadwize);
    Task_sleep(10);
    MotorSetSpeed(motorId, InitialDispenserSpeed);
    CurrentDispenserSpeed[DispenserId] = InitialDispenserSpeed;
    return OK;
}

uint32_t IDS_HomeDispenser (uint32_t DispenserId, uint32_t speed , callback_fptr callback)
{
    assert(DispenserId < MAX_SYSTEM_DISPENSERS);
    //if (DispensersAlarmState[DispenserId] == true)
    //    return ERROR;

    if (FPGA_Read_limit_Switches(Dispenser_Id_to_LS_Id[DispenserId]) == LIMIT)
    {
        Report("IDS_HomeDispenser - Disp is full",__FILE__,Dispenser_Id_to_LS_Id[DispenserId],(int)DispenserId,RpWarning,LIMIT,0);
        return OK;
    }
    if (Get_MidTank_Pressure_Sensor(DispenserId)<0.2)
    {
        Report("IDS_HomeDispenser - Midtank is empty",__FILE__,Get_MidTank_Int100_Sensor(DispenserId),(int)DispenserId,RpWarning,LIMIT,0);
        return ERROR;
    }
    //if Safety is active
        //if safety is upper position or
    if ((HomingActive[DispenserId] == true)||(PrimingActive[DispenserId] == true))
    {
        Report("IDS_HomeDispenser - Homing/priming already active",__FILE__,HomingActive[DispenserId],(int)DispenserId,RpWarning,PrimingActive[DispenserId],0);
        return ERROR;
    }
    else
        HomingActive[DispenserId] = true;

    if (Check_Disp_Safety_Stop_Indication(DispenserId) == true)
    {
        if ((Get_Notification_Disp_UP(DispenserId) == false)||(Get_Notification_Over_Press(DispenserId) == false))
        {
            Report("IDS_HomeDispenser - Bypassing safety",__FILE__,HomingActive[DispenserId],(int)DispenserId,RpWarning,PrimingActive[DispenserId],0);
            Control_TCA9534ByPass(DispenserId,ENABLE);// use ENABLE or DISABLE
        }
    }
    HomingRequestCallback[DispenserId] = callback;

    TimerMotors_t MotorId = HARDWARE_MOTOR_TYPE__MOTO_DISPENSER_1 + DispenserId;
    if ( Dispenser_Id_to_LS_Id[DispenserId] != MAX_GPI)
    {
        //open dispenser valve dispenser to midtank direction
        Control3WayValvesWithCallback ((Valves_t)DispenserId, MidTank_Dispenser, NULL); //direction: MidTank_Dispenser or Dispenser_Mixer
        KeepMicrostep[DispenserId] = MotorsCfg[MotorId].microstep;
        if (Extended_Motor_Param == true)
            Power_Step_01_Dispenser_Mode(DispenserId,Current);
        MotorSetMicroStep(MotorId, 1);
        SysCtlDelay(180000);
        //open dry air valve in the dispenser
        Valve_Set(IDS_Id_to_AirValve[DispenserId], Atm_MidTank_ON);
        Enable_MidTank_Pressure_Reading(DispenserId);
        Read_MidTank_Pressure_Sensor(DispenserId);

        IDS_Dispenser_RefillStarted(DispenserId,1);
        MotorMovetoLimitSwitch (MotorId,1-MotorsCfg[MotorId].directionthreadwize, speed,  Dispenser_Id_to_LS_Id[DispenserId], IDS_HomeDispenserCallback,0);
        CurrentDispenserSpeed[DispenserId] = speed;
        CurrentDispenserSpeed[DispenserId] = (-1*CurrentDispenserSpeed[DispenserId]);
        Report("IDS_HomeDispenser ",__FILE__,__LINE__,(int)DispenserId,RpWarning,speed,0);
        return OK;
    }
    return ERROR;
}
uint32_t IDS_Dispenser_Alarm_On (uint8_t DispenserId)
{
    uint32_t status = OK;
    Report("IDS_Dispenser_Alarm_On",__FILE__,millisecondCounter,(int)DispenserId,RpWarning,0,0);
    DispensersAlarmState[DispenserId] = true;
    TimerMotors_t MotorId = HARDWARE_MOTOR_TYPE__MOTO_DISPENSER_1 + DispenserId;
    status |= MotorAbortMovetoLimitSwitch(MotorId);
    Valve_Set(IDS_Id_to_AirValve[DispenserId], Atm_MidTank_OFF);
    Enable_MidTank_Pressure_Reading(DispenserId);
    if (Extended_Motor_Param == true)
        Power_Step_01_Dispenser_Mode(DispenserId,Voltage);
    status |= MotorSetMicroStep(MotorId, KeepMicrostep[DispenserId]);
    status |= MotorStop(DispenserId, Hard_Hiz);
    CurrentDispenserSpeed[DispenserId] = 0;
    JobEndReason = JOB_OUT_OF_DYE;
    return status;
}
uint32_t IDS_Dispenser_Alarm_Off (uint8_t DispenserId)
{
    uint32_t status = OK;
    DispensersAlarmState[DispenserId] = false;
    Report("IDS_Dispenser_Alarm_Off",__FILE__,millisecondCounter,(int)DispenserId,RpWarning,0,0);
    return status;
}

uint32_t IDS_StopHomeDispenser (uint32_t DispenserId)
{
    assert(DispenserId < MAX_SYSTEM_DISPENSERS);

    Report("IDS_StopHomeDispenser",__FILE__,millisecondCounter,(int)DispenserId,RpWarning,(int)HomingActive[DispenserId],0);
    if ((HomingActive[DispenserId] == false)&&( PrimingActive[DispenserId] == false))
    {
        LOG_ERROR (DispenserId,"Homing not active");
        return ERROR;
    }

    TimerMotors_t MotorId = (DispenserId)+HARDWARE_MOTOR_TYPE__MOTO_DISPENSER_1;
    MotorAbortMovetoLimitSwitch(MotorId);
    //close dry air valve in the dispenser
    Disable_MidTank_Pressure_Reading(DispenserId);
    Valve_Set(IDS_Id_to_AirValve[DispenserId], Atm_MidTank_OFF);
    Control3WayValvesWithCallback ((Valves_t)DispenserId, MidTank_Dispenser, NULL); //direction: MidTank_Dispenser or Dispenser_Mixer

    if (HomingActive[DispenserId] == true)
    {
        IDS_StopHomeDispenserBuildPressure(DispenserId);
    }
    if (PrimingActive[DispenserId] == true)
    {
        if (DispenserId == LUBRICANT_DISPENSER)
        {
            Lubricant_2Way_Valve (STOP);
        }
        PrimingActive[DispenserId] = false;
        Control_TCA9534ByPass(DispenserId,DISABLE);// use ENABLE or DISABLE
        if (Extended_Motor_Param == true)
            Power_Step_01_Dispenser_Mode(DispenserId,Voltage);
        MotorSetMicroStep(MotorId, KeepMicrostep[DispenserId]);
        CurrentDispenserSpeed[DispenserId] = 0;
        CurrentDispenserSpeed[DispenserId] = 0;
    }
    return OK;
}
uint32_t IDS_StopHomeDispenserBuildPressure (uint32_t DispenserId)
{
    assert(DispenserId < MAX_SYSTEM_DISPENSERS);

    Report("IDS_StopHomeDispenser and build pressure",__FILE__,millisecondCounter,(int)DispenserId,RpWarning,(int)HomingActive[DispenserId],0);
    if (HomingActive[DispenserId] != true)
    {
        LOG_ERROR (DispenserId,"Homing not active");
        return ERROR;
    }
    else
        HomingActive[DispenserId] = false;
    Control_TCA9534ByPass(DispenserId,DISABLE);// use ENABLE or DISABLE

    TimerMotors_t motorId = (DispenserId)+HARDWARE_MOTOR_TYPE__MOTO_DISPENSER_1;
    MotorAbortMovetoLimitSwitch(motorId);
    //close dry air valve in the dispenser
//////////////////////////////////////////////////
    Read_MidTank_Pressure_Sensor(DispenserId);
    //close dry air valve in the dispenser
    Valve_Set(IDS_Id_to_AirValve[DispenserId], Atm_MidTank_OFF);
    Disable_MidTank_Pressure_Reading(DispenserId);
    //    MotorSetMicroStep(motorId, KeepMicrostep[DispenserId]);
    if (HomingRequestCallback[DispenserId])
    {
        HomingRequestCallback[DispenserId](DispenserId,0);
        HomingRequestCallback[DispenserId] = NULL;
    }
//    HomingActive[DispenserId]= false;
    Report("Start backlash",__FILE__,millisecondCounter,(int)DispenserId,RpWarning,(int)DispenserHomingTime[DispenserId],0);
    DispenserHomingControlId[DispenserId] = AddControlCallback( IDS_HomeDispenserBackMoveCallback, InitialDispenserTimeLag, GetDispenserPressure,motorId, motorId, 0 );
    Task_sleep(10);
    MotorSetDirection(motorId,MotorsCfg[motorId].directionthreadwize);

    MotorSetSpeed(motorId, 1000);
    CurrentDispenserSpeed[DispenserId] = 1000;
    //IDS_Dispenser_RefillEnded ( DispenserId, MotorsCfg[motorId].microstep);

    return OK;
}

uint32_t IDS_CheckDispenserLimitSwitch (LimitSwitchAlarms LS_Id)
{
    int DispenserId;
    if (LS_Id <= LimitSwitchAlarmEmpty_8)
    {
        DispenserId = LS_Id;
    }
    else
    {
        DispenserId = LS_Id-LimitSwitchAlarmEmpty_8;
    }
    if (isMotorConfigured(DispenserId + HARDWARE_MOTOR_TYPE__MOTO_DISPENSER_1)==false)
        return true;  //false is the alarm value
    else
        return FPGA_Read_limit_Switches(Dispenser_Id_to_Alarm_LS_Id[LS_Id]);
}
uint32_t IDS_EmptyDispenserCallback(uint32_t motorId, uint32_t ReadValue)
{
    uint8_t DispenserId = motorId-HARDWARE_MOTOR_TYPE__MOTO_DISPENSER_1;

    Read_MidTank_Pressure_Sensor(DispenserId);
    //close dry air valve in the dispenser
    Valve_Set(IDS_Id_to_AirValve[DispenserId], Atm_MidTank_OFF);
    Disable_MidTank_Pressure_Reading(DispenserId);

    MotorStop(motorId,Hard_Hiz);
    CurrentDispenserSpeed[DispenserId] = 0;
    if (Extended_Motor_Param == true)
        Power_Step_01_Dispenser_Mode(DispenserId,Voltage);
    MotorSetMicroStep(motorId, KeepMicrostep[DispenserId]);
    PrimingActive[DispenserId]= false;
    Control_TCA9534ByPass(DispenserId,DISABLE);// use ENABLE or DISABLE
    if (DispenserId == LUBRICANT_DISPENSER)
    {
        Lubricant_2Way_Valve (STOP);
    }
    Report("End Priming",__FILE__,millisecondCounter,(int)DispenserId,RpWarning,(int)DispenserHomingTime[DispenserId],0);
    //    MotorSetMicroStep(motorId, KeepMicrostep[DispenserId]);
    if (HomingRequestCallback[DispenserId])
    {
        HomingRequestCallback[DispenserId](DispenserId,0);
        HomingRequestCallback[DispenserId] = NULL;
    }
    return OK;
}

uint32_t IDS_EmptyDispenser (uint32_t DispenserId, uint32_t speed , callback_fptr callback)
{
    assert(DispenserId < MAX_SYSTEM_DISPENSERS);

    //if (DispensersAlarmState[DispenserId] == true)
    //    return ERROR;
    if ((HomingActive[DispenserId] == true)||(PrimingActive[DispenserId] == true))
        return ERROR;
    else
        PrimingActive[DispenserId] = true;
    HomingRequestCallback[DispenserId] = callback;
    if (Check_Disp_Safety_Stop_Indication(DispenserId) == true)
    {
        if ((Get_Notification_Disp_Down(DispenserId) == false)||(Get_Notification_Over_Press(DispenserId) == false))
        {
            Report("IDS_EmptyDispenser - Bypassing safety",__FILE__,HomingActive[DispenserId],(int)DispenserId,RpWarning,PrimingActive[DispenserId],0);
            Control_TCA9534ByPass(DispenserId,ENABLE);// use ENABLE or DISABLE
        }
    }
    TimerMotors_t MotorId = HARDWARE_MOTOR_TYPE__MOTO_DISPENSER_1 + DispenserId;
    if ( Dispenser_Id_to_LS_Empty_Id[DispenserId] != MAX_GPI)
    {
        //open dispenser valve dispenser to midtank direction
        Control3WayValvesWithCallback ((Valves_t)DispenserId, Dispenser_Mixer, NULL); //direction: MidTank_Dispenser or Dispenser_Mixer
        if (Extended_Motor_Param == true)
            Power_Step_01_Dispenser_Mode(DispenserId,Current);
        //Valve_Set((Valves_t) request->index, Dispenser_Mixer);
        KeepMicrostep[DispenserId] = MotorsCfg[MotorId].microstep;
        MotorSetMicroStep(MotorId, 1);
        Task_sleep(100);
        //open dry air valve in the dispenser
        //Valve_Set(IDS_Id_to_AirValve[DispenserId], Atm_MidTank_ON);
        if (DispenserId == LUBRICANT_DISPENSER)
        {
            Lubricant_2Way_Valve (START);
        }
        MotorMovetoLimitSwitch (MotorId,MotorsCfg[MotorId].directionthreadwize, speed,  Dispenser_Id_to_LS_Empty_Id[DispenserId], IDS_EmptyDispenserCallback,0);
        CurrentDispenserSpeed[DispenserId] = speed;
        return OK;
    }
    return ERROR;
}