aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Test_Studio/Machine Studio/ApiTests/project.settings
blob: 094fe365328e39d26161639aab3d6898d62bf651 (plain)
1
2
3
{
"$version": "project-settings/v1"
}
#include <Container.h>
#include <DataDef.h>
#include "include.h"
#include "Modules/Control/control.h" //  use for FPGA IO
#include "drivers/FPGA/FPGA_GPIO/FPGA_GPIO.h"//#include "FPGA_GPIO.h"  //  use for FPGA IO
#include "drivers/Valves/Valve.h"
#include "Common/report/report.h"
#include "Modules/Waste/Waste_ex.h"
#include "modules/heaters/heaters_ex.h"
#include <Drivers/I2C_Communication/RFID_NFC/RFIDTagInfo.h>
#include <Drivers/I2C_Communication/RFID_NFC/NFC_MainBaord.h>
#include "Drivers/I2C_Communication/RFID_NFC/logi-tag/LT_RFID.h"
#include <Drivers/I2C_Communication/RFID_NFC/RFID_Waste.h>

#include "Drivers/I2C_Communication/RFID_NFC/NFC.h"
#include <Utilities/RfidTagHandling.h>
#include "PMR/IFS/CartridgeState.pb-c.h"

#include  <PMR/Diagnostics/EventType.pb-c.h>
#include "Modules/AlarmHandling/AlarmHandling.h"
#include "StateMachines/Initialization/PowerOffSequence.h"
#include "drivers/I2C_Communication/ADC_MUX/ADC_MUX.h"
#include "CartridgeValidationRequest.pb-c.h"
#include "CartridgeValidationResponse.pb-c.h"
#include "Modules/General/buttons.h"
#include "modules/General/process.h"
#include "Modules/General/MachineStatus.h"
#include "Modules/IFS/ifs.h"
#include <Drivers/I2C_Communication/I2C_Task.h>
#include <Drivers/I2C_Communication/WHS_Card/D_MAX11614_ADC/WHS_MAX11614_A2D.h>
#include <Drivers/I2C_Communication/WHS_Card/D_Max5805_ADC_Blower/WHS_Blower.h>
#include <Drivers/I2C_Communication/RFID_NFC/RFID_Waste.h>
#include <Drivers/I2C_Communication/WHS_Card/D_AD5272_Rheostat/WHS_Rheostat.h>

uint8_t VocPpmAlarmLimit = 10;//PPM
uint8_t VocPpmLimitForXSec = 10;//Sec
bool ReadingVocEverySec = false;

bool DoorState = OPEN;
uint32_t timeout_counter = 0;
int wasteLevel = 0;
WasteCartridgeEnum SelectedCard = MaxWasteCartridges;
CartridgeStateEnum CartState[MaxWasteCartridges];// = {CartridgeStateOUT,CartridgeStateOUT,CartridgeStateOUT};
uint32_t Cartridge_Cover_Control;
button *CartLed[MaxWasteCartridges] = {0, &cart2, &cart3};
WasteTankStateEnum WasteTankState = WasteTankStateIdle;

extern char WasteEmptyingToken[36+1];
int init = 1;

bool setWasteValve (WasteCartridgeEnum WasteCartridge);

#define WASTE_CARTRIDGE_SIZE 1500
#define WASTE_LEVEL_OVERFLOW 2700
#define WASTE_LEVEL_FULL 2300
#define WASTE_LEVEL_EMPTY 900
#define WASTE_EMPTING_TIMEOUT 1500
double wasteLevelOverflow = WASTE_LEVEL_OVERFLOW;
double wasteLevelFull = WASTE_LEVEL_FULL;
double wasteLevelEmpty = WASTE_LEVEL_EMPTY;
double wasteLevelOverFlow = WASTE_LEVEL_OVERFLOW;

//#define WHS_DEBUG

/////////////////////////////// Cartridges  //////////////////////////////////////
void Waste_StateMachine(void);
void cartCART_INSERTED (WasteCartridgeEnum CartId)
{
    assert (CartId<MaxWasteCartridges);
    if (CartState[CartId] != CartridgeStateOUT)
        Report("Cartridges Cart inserted wrong state", __FILE__, __LINE__, CartId, RpMessage, CartState[CartId], 0);
    CartState[CartId] = CartridgeStateIN;
    Pannel_Leds((CartId == WasteCartridge_middle)?CART_2:CART_3, MODE_ON);
    CartLed[CartId]->color = colorON;

    Report("Cartridges Cart inserted", __FILE__, __LINE__, CartId, RpMessage, CartState[CartId], 0);
}
void cartCART_EXTRACTED(WasteCartridgeEnum CartId) //{called from polling function. set state to out, if was ACTIVE � notify waste module)
{
    assert (CartId<MaxWasteCartridges);
    if (CartState[CartId] == CartridgeStateOUT)
        Report("Cartridges Cart extracted wrong state", __FILE__, __LINE__, CartId, RpMessage, CartState[CartId], 0);

    Report("Cartridges Cart extracted", __FILE__, __LINE__, CartId, RpMessage, CartState[CartId], 0);
    CartState[CartId] = CartridgeStateOUT;
    Pannel_Leds((CartId == WasteCartridge_middle)?CART_2:CART_3, MODE_OFF);
    CartLed[CartId]->color = colorOFF;
    if (init==0)
        WHS_Set_IFS_Clearing_Suction(NUM_OF_MIDTANKS);

}
WasteCartridgeEnum cartSELECT_CART(void) //{ if there is no SELECTED cartridge select the first cartridge in IN state. If there is none, return -1}
{
    //Report("Cartridges select cart", __FILE__, __LINE__, CartState[WasteCartridge_middle], RpMessage, CartState[WasteCartridge_lower], 0);
    if ((CartState[WasteCartridge_middle] == CartridgeStateSELECTED)||(CartState[WasteCartridge_middle] == CartridgeStateACTIVE))
        return WasteCartridge_middle;
    if ((CartState[WasteCartridge_lower]  == CartridgeStateSELECTED)||(CartState[WasteCartridge_lower] == CartridgeStateACTIVE))
        return WasteCartridge_lower;
    //no selected/active cartridge yet
    if (CartState[WasteCartridge_middle] == CartridgeStateIN) {
        CartState[WasteCartridge_middle] = CartridgeStateSELECTED;
        return WasteCartridge_middle;
    }
    if (CartState[WasteCartridge_lower] == CartridgeStateIN) {
        CartState[WasteCartridge_lower] = CartridgeStateSELECTED;
        return WasteCartridge_lower;
    }
    return MaxWasteCartridges;
}

void cartFILLING_START(void) //{set state of SELECTED to ACTIVE}
{
    if (CartState[WasteCartridge_middle] == CartridgeStateSELECTED) {
        Report("Cartridges middle Cart active", __FILE__, __LINE__, WasteCartridge_middle, RpMessage, CartState[WasteCartridge_middle], 0);
        CartState[WasteCartridge_middle] = CartridgeStateACTIVE;
        CartLed[WasteCartridge_middle]->color = BLINK;
    } else if (CartState[WasteCartridge_lower] == CartridgeStateSELECTED) {
        Report("Cartridges lower Cart active", __FILE__, __LINE__, WasteCartridge_lower, RpMessage, CartState[WasteCartridge_lower], 0);
        CartState[WasteCartridge_lower] = CartridgeStateACTIVE;
        CartLed[WasteCartridge_lower]->color = BLINK;
    } else {
        Report("Cartridges start with no selected cartridge", __FILE__, __LINE__, CartState[WasteCartridge_middle], RpMessage, CartState[WasteCartridge_lower], 0);
    }
}

void cartFILLING_END(void)
{
    //{set state of ACTIVE to FULL}
    if (CartState[WasteCartridge_middle] == CartridgeStateACTIVE) {
        CartState[WasteCartridge_middle] = CartridgeStateFULL;
        CartLed[WasteCartridge_middle]->color = colorOFF;
    } else if (CartState[WasteCartridge_lower] == CartridgeStateACTIVE) {
        CartState[WasteCartridge_lower] = CartridgeStateFULL;
        CartLed[WasteCartridge_lower]->color = colorOFF;
    } else {
        Report("Cartridges end with no active cartridge", __FILE__, __LINE__, CartState[WasteCartridge_middle], RpMessage, CartState[WasteCartridge_lower], 0);
    }
    setWasteValve(WasteCartridge_middle);

}

CartridgeStateEnum cartGetState(WasteCartridgeEnum CartId)
{
    assert (CartId<MaxWasteCartridges);
    return CartState[CartId];
}

bool cartGetPresence (WasteCartridgeEnum CartId)
{
    assert (CartId<MaxWasteCartridges);
    if (CartState[CartId] == CartridgeStateOUT)
        return false;
    else
        return true;
}

bool NoCartAvailable()
{
    uint32_t CartId;

    for(CartId = CART_2; CartId <= CART_3; CartId++) {
        if (Is_Cartridge_Present(CartId))
            return false;
    }
    return true;
}

WasteCartridgeEnum cartGetActiveCart()
{
    uint32_t CartId;

    for (CartId = WasteCartridge_middle; CartId < MaxWasteCartridges; CartId++) {
        if (CartState[CartId] == CartridgeStateACTIVE)
            return CartId;
    }
    return MaxWasteCartridges;
}

WasteCartridgeEnum cartNotAllFull()
{
    uint32_t CartId;

    for (CartId = WasteCartridge_middle; CartId < MaxWasteCartridges; CartId++) {
        if (CartState[CartId] != CartridgeStateFULL)
            return true;
    }
    return false;
}

bool SetWastePump( bool power)
{
    if ( power == OPEN ) {
        if (WHS_Type == WHS_TYPE_UNKNOWN) {
            Pumps_Control(WHS_WTANKPUMP2, OPEN); //waste_pump_power_on();
        } else { //new WHS
            Trigger_SetWHSPump(OPEN);
        }
        return OPEN;
    } else {
        if (WHS_Type == WHS_TYPE_UNKNOWN) {
            Pumps_Control(WHS_WTANKPUMP2, CLOSE); //waste_pump_power_on();
        } else { //new WHS
            Trigger_SetWHSPump(CLOSE);
        }
        return CLOSE;
    }
}

bool setWasteValve (WasteCartridgeEnum WasteCartridge)
{
    bool direction;

    if (WasteCartridge == WasteCartridge_lower) {
        direction = true;
    } else {
        direction = false;
    }

    if (WHS_Type == WHS_TYPE_UNKNOWN) {
        Valve_Set(VALVE_WASTE_TANK,direction);
    } else { //new WHS
        Trigger_SetWHSValveWatseCartridge(direction);
    }
    return direction;
}

bool RdWasteTankEmptySensor()
{
    //double WasteLevel = 0.0;
#ifndef WHS_DEBUG
    if (WHS_Type == WHS_TYPE_UNKNOWN) {
        return WHS_GPI_WCONTAINER_WARN();
    }
    else
#endif
    { //new WHS
        //WasteLevel = GetWHSWasteTankLevelMiliLiter();
        if (wasteLevel < wasteLevelEmpty)
            return 1; //Empty
    }
    return 0;
}

bool RdWasteTankFullSensor()
{
    //double WasteLevel = 0.0;
#ifndef WHS_DEBUG
    if (WHS_Type == WHS_TYPE_UNKNOWN) {
        return WHS_GPI_WCONTAINER_FULL();
    }
    else
#endif
    { //new WHS
        //WasteLevel = GetWHSWasteTankLevelMiliLiter();
        if (wasteLevel >= wasteLevelFull)
            return 1; //full
    }
    return 0;
}

bool RdWasteTankOverFlowSensor()
{
    //double WasteLevel = 0.0;
#ifndef WHS_DEBUG
    if (WHS_Type == WHS_TYPE_UNKNOWN) {
        return WHS_GPI_WASTE_OVERFULL();
    }
    else
#endif
    {//new WHS
        //WasteLevel = GetWHSWasteTankLevelMiliLiter();
        if (wasteLevel > wasteLevelOverflow)
            return 1; //overflow
    }
    return 0;
}

float WHS_GetCartridgeFillPercent()
{
    return (100 - (((wasteLevel - wasteLevelEmpty) * 100) / WASTE_CARTRIDGE_SIZE));
}
int WHS_GetCartridgeFill()
{
    return (wasteLevelFull - wasteLevel);
}
bool WHS_IsContainerFull()
{
    return RdWasteTankFullSensor();
}

bool WHS_IsContainerEmpty()
{
    return RdWasteTankEmptySensor();
}

bool WHS_IsContainerOverflow()
{
    return RdWasteTankOverFlowSensor();
}

bool WHS_WasteCartridgeLowerPresent()
{
    return Is_Cartridge_Present(CART_3);
}

bool WHS_WasteCartridgeMiddlePresent()
{
    return Is_Cartridge_Present(CART_2);
}

bool WHS_IsEmptying()
{
    if (WasteTankState == WasteTankStateEmptying) {
        return true;
    } else {
        return false;
    }
}

void Waste_Init()
{
    CartState[WasteCartridge_middle] = CartridgeStateOUT;
    CartState[WasteCartridge_lower] = CartridgeStateOUT;
    DoorState = OPEN;
}

bool cartCart_door()//Polled by polling function. Notify waste. Poll each 1 second. During active filling poll each 100msec
{
    if(Get_COVER_1_State(CartridgesDoor))//to check the polarity
    {
        DoorState = OPEN;
    }
    else
    {
        DoorState = CLOSE;
    }
#ifdef WHS_DEBUG
    DoorState = CLOSE;
#endif
    return DoorState;
}

uint32_t Waste_DoorOpenDuringEmptying(uint32_t IfIndex, uint32_t ReadValue)
{
    cartCart_door();
    if ((DoorState == OPEN) && (WasteTankState == WasteTankStateEmptying)) {
        SetWastePump(CLOSE);
        WasteTankState = WasteTankStatePaused;
        Report("move to WasteTankStatePaused", __FILE__, __LINE__, DoorState, RpMessage, WasteTankState, 0);
    }
    if ((DoorState == CLOSE) && (WasteTankState == WasteTankStatePaused)) {
        if (cartGetActiveCart() != MaxWasteCartridges) {
            SetWastePump(OPEN);
            WasteTankState = WasteTankStateEmptying;
            Report("return to WasteTankStateEmptying", __FILE__, __LINE__, DoorState, RpMessage, WasteTankState, 0);
        }
    }
    return OK;
}

void Waste_StateMachine_OneSecond_Call(void)
{
    static WasteTankStateEnum prev_state = 0;
    static int cart, prev_wasteLevel = 0;
    static int insertUpdate[3] = {0, 0, 0};

    //call cartridge state
    if ((Is_Cartridge_Present(CART_2) != cartGetPresence(WasteCartridge_middle)) || (init)) {
        if (Is_Cartridge_Present(CART_2)) {
            cartCART_INSERTED(WasteCartridge_middle);
            insertUpdate[CARTRIDGE_SLOT__WasteMiddle-1] = 1;
        } else {
            cartCART_EXTRACTED(WasteCartridge_middle);
        }
    }
    if ((Is_Cartridge_Present(CART_3) != cartGetPresence(WasteCartridge_lower)) || (init)) {
        if (Is_Cartridge_Present(CART_3)) {
            cartCART_INSERTED(WasteCartridge_lower);
            insertUpdate[CARTRIDGE_SLOT__WasteLower-1] = 1;
        } else {
            cartCART_EXTRACTED(WasteCartridge_lower);
        }
    }

    //update ppc
    for (cart = WasteCartridge_middle; cart <= WasteCartridge_lower; cart++) {
        if (WasteEmptyingToken[0]) {
            if (insertUpdate[cart]) {
                CartridgeStateUpdate(cart, cart-1, CARTRIDGE_STATE__Inserted, 0);
                insertUpdate[cart] = 0;
            }
            if (Is_Cartridge_Present(cart+1)) {
                CartridgeStateUpdate(cart, cart-1, CARTRIDGE_STATE__Present, 0);
            } else {
                CartridgeStateUpdate(cart, cart-1, CARTRIDGE_STATE__Absent, 0);
            }
        }
    }

    //call door state
    cartCart_door();

    //call waste tank level
#ifndef WHS_DEBUG
    wasteLevel = GetWHSWasteTankLevelMiliLiter();
#endif

    if ((WasteTankState != prev_state) || (abs(wasteLevel - prev_wasteLevel) > 50)) {
        Report("Waste_StateMachine_OneSecond_Call", __FILE__, WasteTankState, SelectedCard, RpMessage, wasteLevel, 0);
        prev_state = WasteTankState;
        prev_wasteLevel = wasteLevel;
    }

    //call state machine
    Waste_StateMachine();

    if(init)
        init = 0;

#ifdef WHS_DEBUG
            wasteLevel += 50;
#endif
}

void Waste_StateMachine(void)
{
    uint32_t activeCart;
    char str[100];
    uint32_t rc;

    switch (WasteTankState)
    {
        case WasteTankStateIdle:
            if(WHS_IsContainerOverflow()) {
                AlarmHandlingSetAlarm( EVENT_TYPE__WASTE_CONTAINER_OVERFLOW,  true);
            } else {
                AlarmHandlingSetAlarm( EVENT_TYPE__WASTE_CONTAINER_OVERFLOW,  false);
            }
            if (cartNotAllFull() == true) {
                AlarmHandlingSetAlarm( EVENT_TYPE__ALL_WASTE_CARTRIDGES_FULL,  false);
            }
            if(WHS_IsContainerFull()) {
                //check if power down in process
                if ( PowerOffInProcessGetState() ) {
                    //Report("Power-down in process", __FILE__, __LINE__, 0, RpMessage, 0, 0);
                    break;
                }

                // select cartridge
                SelectedCard = cartSELECT_CART();
                if (SelectedCard == MaxWasteCartridges) {
                    //Report("No Available cart", __FILE__, __LINE__, SelectedCard, RpMessage, 0, 0);
                    AlarmHandlingSetAlarm( EVENT_TYPE__NO_WASTE_CARTRIDGE_AVAILABLE,  true);
                    break;
                } else {
                    AlarmHandlingSetAlarm( EVENT_TYPE__NO_WASTE_CARTRIDGE_AVAILABLE,  false);
                }

                //check door
                //moved door handling down - I want to see the alarm even if the door is open
                if (DoorState == OPEN) {
                    //Report("Close cartridge cover", __FILE__, __LINE__, DoorState, RpMessage, 0, 0);
                    break;
                }
                // check RFID - check cartridge OK (inkEmpty)
                // RFID change status - set WasteEmpty
                rc = RFID_Update_Waste_Empty(SelectedCard);
                Report("RFID_Update_Waste_Empty", __FILE__, __LINE__, SelectedCard, RpMessage, rc, 0);

                //move to next state
                WasteTankState = WasteTankStateFull;
                Report("move to WasteTankStateFull", __FILE__, __LINE__, DoorState, RpMessage, WasteTankState, 0);
            }
            break;
        case WasteTankStateFull:
            //set cart Active
            cartFILLING_START();

            // set valve selection
            activeCart = cartGetActiveCart();
            //Report("WasteTankStateEmptying set valve", __FILE__, __LINE__, activeCart, RpMessage, 0, 0);
            setWasteValve(activeCart);

            // set count down
            timeout_counter = 1;
            AlarmHandlingSetAlarm( EVENT_TYPE__WASTE_CONTAINER_EMPTYING_TIMEOUT,  false);

            // set emptying limit
            wasteLevelEmpty = wasteLevel - WASTE_CARTRIDGE_SIZE;
            wasteLevelFull = wasteLevel;
            waste_seq_step1_cont();

            // start a timer to observe door opening
            Cartridge_Cover_Control = AddControlCallback("Cartridge Cover Door", Waste_DoorOpenDuringEmptying, 100,  cartCart_door, 0, 0, 0);
            Report("add control Cartridge Cover Door", __FILE__, __LINE__, 0, RpMessage, 0, 0);

            SetWastePump(OPEN);
            Report("WasteTankStateEmptying set Pump Open", __FILE__, activeCart, wasteLevel, RpMessage, wasteLevelEmpty, 0);

            //start  emptying
            // RFID change status - set wasteFill
            rc = RFID_Update_Waste_Fill(activeCart);
            Report("RFID_Update_Waste_Fill", __FILE__, __LINE__, activeCart, RpMessage, rc, 0);
            WasteTankState = WasteTankStateEmptying;
            CartridgeStateUpdate(activeCart, activeCart-1, CARTRIDGE_STATE__Emptying, 0);
            break;
        case WasteTankStateEmptying:
            // if time out or emptying done - idle
            activeCart = cartGetActiveCart();
            if (timeout_counter++ > WASTE_EMPTING_TIMEOUT) {
                SetWastePump(CLOSE);
                cartFILLING_END();
                WasteTankState = WasteTankStateIdle;
                usnprintf(str, 100, "WasteTankStateEmptying Timeout. time:%d:%d volume:%d", timeout_counter/60, timeout_counter%60, WHS_GetCartridgeFill());
                Report(str, __FILE__, __LINE__, 0, RpMessage, 0, 0);
                CartridgeStateUpdate(activeCart, activeCart-1, CARTRIDGE_STATE__Error, WHS_GetCartridgeFillPercent());
                AlarmHandlingSetAlarm( EVENT_TYPE__WASTE_CONTAINER_EMPTYING_TIMEOUT,  true);
                RemoveControlCallback(Cartridge_Cover_Control, Waste_DoorOpenDuringEmptying);
                timeout_counter = 0;
            } else if (WHS_IsContainerEmpty()) {
                SetWastePump(CLOSE);
                cartFILLING_END();
                waste_seq_cont_stop();
                // RFID change status - set wasteFull
                rc = RFID_Update_Waste_Full(activeCart);
                Report("RFID_Update_Waste_Full", __FILE__, __LINE__, activeCart, RpMessage, rc, 0);
                WasteTankState = WasteTankStateIdle;
                RemoveControlCallback(Cartridge_Cover_Control, Waste_DoorOpenDuringEmptying);
                //if (cartNotAllFull() == false)
                    AlarmHandlingSetAlarm( EVENT_TYPE__ALL_WASTE_CARTRIDGES_FULL,  true);
                usnprintf(str, 100, "WasteTankStateEmptying done. time:%d:%d volume:%d", timeout_counter/60, timeout_counter%60, WHS_GetCartridgeFill());
                Report(str, __FILE__, __LINE__, 0, RpMessage, 0, 0);
                CartridgeStateUpdate(activeCart, activeCart-1, CARTRIDGE_STATE__EmptyingCompleted, WHS_GetCartridgeFillPercent());
                timeout_counter = 0;
            }
            if (WasteTankState == WasteTankStateEmptying)
                CartridgeStateUpdate(activeCart, activeCart-1, CARTRIDGE_STATE__Emptying, WHS_GetCartridgeFillPercent());
#ifdef WHS_DEBUG
            wasteLevel -= 100;
            timeout_counter += 10;
#endif
            break;
        case WasteTankStatePaused:
            Report("WasteTankStatePaused...", __FILE__, __LINE__, 0, RpMessage, 0, 0);
            activeCart = cartGetActiveCart();
            if (activeCart == MaxWasteCartridges)
            {
                SetWastePump(CLOSE);
                cartFILLING_END();
                waste_seq_cont_stop();
                // RFID change status - TBD
                WasteTankState = WasteTankStateIdle;
                RemoveControlCallback(Cartridge_Cover_Control, Waste_DoorOpenDuringEmptying);
                if (cartNotAllFull() == false)
                    AlarmHandlingSetAlarm( EVENT_TYPE__ALL_WASTE_CARTRIDGES_FULL,  true);
                Report("WasteTankStatePaused done", __FILE__, __LINE__, 0, RpMessage, 0, 0);
                timeout_counter = 0;
                CartridgeStateUpdate(activeCart, activeCart-1, CARTRIDGE_STATE__Error, WHS_GetCartridgeFillPercent());
            }
            break;
        default:
            Report("wrong state", __FILE__, WasteTankState, 0, RpMessage, SelectedCard, 0);
            break;
    }
}
uint32_t Waste_CheckState(int *AlarmId)
{
    //check if the waste is ready to run - waste level not above overflow level and no cartridge in the slots
    if (wasteLevel > wasteLevelOverflow)
    {
        Report("cannot start a job with waste tank overflow", __FILE__, __LINE__, wasteLevel, RpMessage, wasteLevelOverflow, 0);
        JobEndReason = JOB_SAFETY_CRITICAL_ALARM;
        usnprintf(AlarmReasonStr, 100, "cannot start a job with waste tank overflow");
        AlarmHandlingSetAlarm( EVENT_TYPE__WASTE_CONTAINER_OVERFLOW,  true);
        *AlarmId = EVENT_TYPE__WASTE_CONTAINER_OVERFLOW;
        //PrepareReady(Module_Waste,ModuleFail);
        return JOB_SAFETY_CRITICAL_ALARM;
    }
    if ((WHS_IsEmptying())||(NoCartAvailable()))
    {
        //PrepareReady(Module_Waste,ModuleDone);
        return JOB_OK;
    }
    else
    {
        Report("cannot start a job with cartridges in the IFS", __FILE__, __LINE__, wasteLevel, RpMessage, wasteLevelOverflow, 0);
        JobEndReason = JOB_WASTE_HANDLING_PROBLEM;
        AlarmHandlingSetAlarm( EVENT_TYPE__ALL_WASTE_CARTRIDGES_FULL,  true);
        *AlarmId = EVENT_TYPE__ALL_WASTE_CARTRIDGES_FULL;
        usnprintf(AlarmReasonStr, 100, "cannot start a job with cartridges in the IFS");
        //PrepareReady(Module_Waste,ModuleFail);
        return JOB_WASTE_HANDLING_PROBLEM;
    }
}
int Waste_Prepare_Timeout = 0;
bool WHS_FlowReady = false,HeadIn_FlowReady = false,HeadOut_FlowReady = false;
uint32_t WasteReadyControlId = 0xFF;
float AllowedRangeForHeadBlowerDeviation = 0.07,AllowedRangeForWasteBlowerDeviation = 0.20;
void setWastePrepareValues(float HeadLimit,float WasteLimit)
{
    AllowedRangeForHeadBlowerDeviation = HeadLimit;
    AllowedRangeForWasteBlowerDeviation = WasteLimit;
}
uint32_t Waste_PrepareCallbak(uint32_t IfIndex, uint32_t ReadValue)
{
    bool ready = false, headready = false,whsready = false;
    double HeadFlow = GetWHSAirFlow(HEAD_FLOW_METER);
    double HeadIn_Flow =  PressureSensorGetPressure(HEAD_FAN_RIGHT);
    double HeadOut_Flow = PressureSensorGetPressure(HEAD_FAN_LEFT);
    if(WHS_Type == WHS_TYPE_UNKNOWN)
        WHS_FlowReady = true; //LP machine
    if ((HeadFlow<(headairflow*(1+AllowedRangeForWasteBlowerDeviation)))
            &&(HeadFlow>(headairflow*(1-AllowedRangeForWasteBlowerDeviation))))
    {
        if (WHS_FlowReady == false)
            Report("Module waste WHS_FlowReady ready", __FILE__, __LINE__, (int)(HeadFlow*100), RpMessage, WHS_FlowReady, 0);
        WHS_FlowReady = true;
    }
    if ((HeadIn_Flow<(headBlowersFlow[0]*(1+AllowedRangeForHeadBlowerDeviation)))
            &&(HeadIn_Flow>(headBlowersFlow[0]*(1-AllowedRangeForHeadBlowerDeviation))))
    {
        if (HeadIn_FlowReady == false)
            Report("Module waste HeadIn_FlowReady ready", __FILE__, __LINE__, (int)(HeadIn_Flow*100), RpMessage, HeadIn_FlowReady, 0);
        HeadIn_FlowReady = true;
    }
    if ((HeadOut_Flow<(headBlowersFlow[1]*(1+AllowedRangeForHeadBlowerDeviation)))
            &&(HeadOut_Flow>(headBlowersFlow[1]*(1-AllowedRangeForHeadBlowerDeviation))))
    {
        if (HeadOut_FlowReady == false)
            Report("Module waste HeadOut_FlowReady ready", __FILE__, __LINE__, (int)(HeadOut_Flow*100), RpMessage, WHS_FlowReady, 0);
        HeadOut_FlowReady = true;
    }
    if (Head_Type <=HEAD_TYPE_FLAT)
        headready = true;
    else if ((HeadIn_FlowReady == true)&&(HeadOut_FlowReady == true))
        headready = true;
    if (WHS_Type == WHS_TYPE_UNKNOWN)
        whsready = true;
    else if (WHS_FlowReady == true)
        whsready = true;
    if ((headready == true)&&(whsready == true))
        ready = true;
    if ((Waste_Prepare_Timeout%30 == 0)||(Waste_Prepare_Timeout>250))
    {
        Report("Module waste preparing values", __FILE__, (int)(HeadFlow*100), (int)(HeadIn_Flow*100), RpMessage, (int)(HeadOut_Flow*100), 0);
    }
    if (Waste_Prepare_Timeout++>300)
    {
        SafeRemoveControlCallback(WasteReadyControlId,Waste_PrepareCallbak);
        WasteReadyControlId = 0xFF;
        JobEndReason = JOB_PRESSURE_ALARM;
        usnprintf(AlarmReasonStr, 100, "Module waste prepare - air flow not stabilized");
        Report("Module waste prepare failed!", __FILE__, __LINE__, headready, RpMessage, headready, 0);
        PrepareReady(Module_Waste,ModuleFail);
    }
    if (ready == true)
    {
        SafeRemoveControlCallback(WasteReadyControlId,Waste_PrepareCallbak);
        WasteReadyControlId = 0xFF;
        Report("Module waste prepare ready!", __FILE__, __LINE__, headready, RpMessage, headready, 0);
        PrepareReady(Module_Waste,ModuleDone);
    }
    Report("Module waste prepare", __FILE__, __LINE__, headready, RpMessage, whsready, 0);
    return OK;
}
uint32_t Waste_Check_Flows(void)
{
    WHS_FlowReady = false;HeadIn_FlowReady = false;HeadOut_FlowReady = false;

    if (WasteReadyControlId != 0xFF)
        RemoveControlCallback(WasteReadyControlId,Waste_PrepareCallbak);
    Waste_Prepare_Timeout = 0;
    //check that blowers are within 10% of designated flow: WHS, head blowers
    WasteReadyControlId = AddControlCallback("Cartridge Cover Door", Waste_PrepareCallbak, eOneSecond,  TemplateDataReadCBFunction, 0, 0, 0);
    Report("Waste_Check_Flows prepare", __FILE__, __LINE__, Head_Type, RpMessage, WHS_Type, 0);
    return OK;
}
uint32_t Waste_Prepare(void)
{
	if (HeaterCheckReady() == true)
	{
	    HeadBlowersV0Init();
	}
    Report("Module waste prepare", __FILE__, HeaterCheckReady(), Head_Type, RpMessage, WHS_Type, 0);
    return OK;
}

bool WHS_IsVocPpmOverAlarmLimit()
{
    static uint8_t counter = 0;
    uint8_t VocPpmAlarmLimit90Percent = 0;
    uint32_t Temp = 0;

    Temp = (uint32_t)VocPpmAlarmLimit * 90;
    Temp /= 100;
    VocPpmAlarmLimit90Percent = (uint8_t)Temp;

    if( (  Latest_Gas_Sens_PPM > VocPpmAlarmLimit                                        ) ||     //PPM
        ( (Latest_Gas_Sens_PPM > VocPpmAlarmLimit90Percent) && (ReadingVocEverySec == true) )     ) //Hysteresis
    {
        //Report("VOC nearing alarm state", __FILE__, (int)(Latest_Gas_Sens_PPM*100), VocPpmAlarmLimit, RpMessage, counter, 0);
        //reading every sec
        ReadingVocEverySec = true;
        if(counter < 0xFF)
        {
            counter++;
        }

        /*if(counter > VocPpmLimitForXSec)//Sec
        {
            AlarmHandlingSetAlarm(EVENT_TYPE__VOC_SENSOR_ALARM_SLOPE,true);
            return true;//Buzzer ON if defined
        }*/
    }
    else
    {
        AlarmHandlingSetAlarm(EVENT_TYPE__VOC_SENSOR_ALARM_SLOPE,false);
        //move back to noraml reading every Min.
        ReadingVocEverySec = false;//Turn off the buzzer on the first time sampling a measurment lower than (VocPpmAlarmLimit - 10%)
        counter = 0;
    }

    return false;
}