diff --git a/CustomDataStructures.h b/CustomDataStructures.h index 6b69bb8f8bc5a1e08f6faaf6059aa31bc36c1efa..05992442c185d1396ef6365da52d1bd7f668e596 100644 --- a/CustomDataStructures.h +++ b/CustomDataStructures.h @@ -118,6 +118,7 @@ typedef struct menuData_ { int _position; int _selection; bool _repaint; + void (*_selectionFunction)(void); } MenuData; #endif diff --git a/brew.h b/brew.h index bbe5b587d9e6e2dd414c9ebbd7823e9e30b9eb35..d0e137e293828a38a03cb9be0ba08299705b2ed2 100644 --- a/brew.h +++ b/brew.h @@ -17,6 +17,14 @@ #include "CustomDataStructures.h" #include "debug.h" +// ++++++++++++++++++++++++ FUNCTIONS (used in configuration) +++++++++++++++++++++++++++++++++ +void runMainMenuSelection(); +void runStartFromStageSelection(); +void runBeerProfileSelection(); +void runStageSelection(); +void runMaltSelection(); +void runSettingsSelection(); + #include "config.h" #include "Melody.h" @@ -38,13 +46,9 @@ void xWelcomeUser(); void runMenu(); -void runSettingsSelection(); +void runMenuProcessor( MenuData *data ); -void runMaltSelection(); - -void runStageSelection(); - -void runBeerProfileSelection(); +void runStageSelection_Generic( unsigned long * selectedStageTime, int *selectedStageTemperature); void xStartStage( unsigned long *stageTime, int *stageTemperature, eCookingStages nextStage, bool bPurgePump, bool bSetFinalYield, bool bSetTime, bool bSetTemperature ); @@ -52,10 +56,6 @@ void xStartStageHeadless( eCookingStages nextStage, bool bPurgePump ); void xStartStageInteractive( unsigned long *stageTime, int *stageTemperature, eCookingStages nextStage ); -void runStartFromStageSelection(); - -void runMainMenuSelection(); - void xCountTheTime( int temperatureRange, boolean bAverageUpDown ); bool isTimeLeft(); diff --git a/brew.ino b/brew.ino index 4c821e3ad4c459b51072898a7a8a7789d8143671..4c306e1a52576938f4773300b7d20a65c8d2b777 100644 --- a/brew.ino +++ b/brew.ino @@ -18,25 +18,12 @@ eBeerProfile beerProfile; eMenuType eMenuType; -MenuData mdMainMenu = { ._title = MENU_MAIN_TITLE, ._dialog = MENU_MAIN_DIALOG, ._position = MENU_MAIN_INIT_POSITION, ._selection = MENU_MAIN_INIT_SELECTION, ._repaint = MENU_MAIN_INIT_REPAINT }; -MenuData mdStartFromStageMenu = { ._title = MENU_START_TITLE, ._dialog = MENU_START_DIALOG, ._position = MENU_START_INIT_POSITION, ._selection = MENU_START_INIT_SELECTION, ._repaint = MENU_START_INIT_REPAINT }; -MenuData mdBeerProfileMenu = { ._title = MENU_PROFILE_TITLE, ._dialog = MENU_PROFILE_DIALOG, ._position = MENU_PROFILE_INIT_POSITION, ._selection = MENU_PROFILE_INIT_SELECTION, ._repaint = MENU_PROFILE_INIT_REPAINT }; -MenuData mdStageMenu = { ._title = MENU_STAGE_TITLE, ._dialog = MENU_STAGE_DIALOG, ._position = MENU_STAGE_INIT_POSITION, ._selection = MENU_STAGE_INIT_SELECTION, ._repaint = MENU_STAGE_INIT_REPAINT }; -MenuData mdMaltMenu = { ._title = MENU_MALT_TITLE, ._dialog = MENU_MALT_DIALOG, ._position = MENU_MALT_INIT_POSITION, ._selection = MENU_MALT_INIT_SELECTION, ._repaint = MENU_MALT_INIT_REPAINT }; -MenuData mdSettingsMenu = { ._title = MENU_SETTINGS_TITLE, ._dialog = MENU_SETTINGS_DIALOG, ._position = MENU_SETTINGS_INIT_POSITION, ._selection = MENU_SETTINGS_INIT_SELECTION, ._repaint = MENU_SETTINGS_INIT_REPAINT }; - -//eMainMenuOptions eMainMenuPosition; -//eMainMenuOptions eMainMenuSelection; -eStageMenuOptions eStartFromStageMenuPosition; -eStageMenuOptions eStartFromStageMenuSelection; -eBeerProfileMenuOptions eBeerProfileMenuPosition; -eBeerProfileMenuOptions eBeerProfileMenuSelection; -eStageMenuOptions eStageMenuPosition; -eStageMenuOptions eStageMenuSelection; -eMaltMenuOptions eMaltMenuPosition; -eMaltMenuOptions eMaltMenuSelection; -eSettingsMenuOptions eSettingsMenuPosition; -eSettingsMenuOptions eSettingsMenuSelection; +MenuData mdMainMenu = { ._title = MENU_MAIN_TITLE, ._dialog = MENU_MAIN_DIALOG, ._position = MENU_MAIN_INIT_POSITION, ._selection = MENU_MAIN_INIT_SELECTION, ._repaint = MENU_MAIN_INIT_REPAINT, ._selectionFunction = MENU_MAIN_FUNCTION }; +MenuData mdBeerProfileMenu = { ._title = MENU_PROFILE_TITLE, ._dialog = MENU_PROFILE_DIALOG, ._position = MENU_PROFILE_INIT_POSITION, ._selection = MENU_PROFILE_INIT_SELECTION, ._repaint = MENU_PROFILE_INIT_REPAINT, ._selectionFunction = MENU_PROFILE_FUNCTION }; +MenuData mdStageMenu = { ._title = MENU_STAGE_TITLE, ._dialog = MENU_STAGE_DIALOG, ._position = MENU_STAGE_INIT_POSITION, ._selection = MENU_STAGE_INIT_SELECTION, ._repaint = MENU_STAGE_INIT_REPAINT, ._selectionFunction = MENU_STAGE_FUNCTION }; +MenuData mdMaltMenu = { ._title = MENU_MALT_TITLE, ._dialog = MENU_MALT_DIALOG, ._position = MENU_MALT_INIT_POSITION, ._selection = MENU_MALT_INIT_SELECTION, ._repaint = MENU_MALT_INIT_REPAINT, ._selectionFunction = MENU_MALT_FUNCTION }; +MenuData mdSettingsMenu = { ._title = MENU_SETTINGS_TITLE, ._dialog = MENU_SETTINGS_DIALOG, ._position = MENU_SETTINGS_INIT_POSITION, ._selection = MENU_SETTINGS_INIT_SELECTION, ._repaint = MENU_SETTINGS_INIT_REPAINT, ._selectionFunction = MENU_SETTINGS_FUNCTION }; +MenuData mdStartFromStageMenu = { ._title = MENU_START_TITLE, ._dialog = MENU_START_DIALOG, ._position = MENU_START_INIT_POSITION, ._selection = MENU_START_INIT_SELECTION, ._repaint = MENU_START_INIT_REPAINT, ._selectionFunction = MENU_START_FUNCTION }; // ++++++++++++++++++++++++ Global Variables ++++++++++++++++++++++++ boolean cooking; @@ -147,10 +134,10 @@ void isr () { // Interrupt service routine is executed when a HIGH to LOW tr rotaryEncoderVirtualPosition = rotaryEncoderVirtualPosition - rotaryEncoderSingleStep; } if (rotaryEncoderVirtualPosition > rotaryEncoderMaxPosition) { - rotaryEncoderVirtualPosition = rotaryEncoderMinPosition; + rotaryEncoderVirtualPosition = rotaryEncoderMaxPosition; } if (rotaryEncoderVirtualPosition < rotaryEncoderMinPosition) { - rotaryEncoderVirtualPosition = rotaryEncoderMaxPosition; + rotaryEncoderVirtualPosition = rotaryEncoderMinPosition; } break; @@ -301,17 +288,6 @@ void setup() { // ++++++++++++++++++++++++ State Machine ++++++++++++++++++++++++ eMenuType = eMenuType_Main; - //eMainMenuPosition = MENU_MAIN_INIT_POSITION; - //eMainMenuSelection = MENU_MAIN_INIT_SELECTION; - eBeerProfileMenuPosition = eBeerProfileMenu_Basic; - eBeerProfileMenuSelection = eBeerProfileMenu_NULL; - eStageMenuPosition = eStageMenu_Startpoint; - eStageMenuSelection = eStageMenu_NULL; - eMaltMenuPosition = eMaltMenu_CastleMalting_Chteau_Pilsen_2RS; - eMaltMenuSelection = eMaltMenu_NULL; - eSettingsMenuPosition = eSettingsMenu_PT100_Element; - eSettingsMenuSelection = eSettingsMenu_NULL; - cookingStage = eCookingStage_Startpoint; beerProfile = eBeerProfile_Basic; // ++++++++++++++++++++++++ Global Variables ++++++++++++++++++++++++ @@ -394,634 +370,620 @@ void loop() { // ######################### FUNCTIONS ######################## -void runMenu() { -#ifdef DEBUG_OFF - boolean debug_go = repaint; - if (debug_go) { - debugPrintFunction("runMenu"); - debugPrintVar("repaint", repaint); - debugPrintVar("eMenuType", eMenuType); - debugPrintVar("rotaryEncoderVirtualPosition", rotaryEncoderVirtualPosition); - } -#endif - - switch (eMenuType) { - case eMenuType_Main: { - //eMainMenuPosition = static_cast(rotaryEncoderVirtualPosition); - mdMainMenu._position = rotaryEncoderVirtualPosition; - mdMainMenu._repaint = repaint; - repaint = displayGenericMenu( &lcd, &mdMainMenu ); - //repaint = displayMainMenu( &lcd, eMainMenuPosition, repaint ); - if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) { - mdMainMenu._selection = mdMainMenu._position; - //eMainMenuSelection = eMainMenuPosition; - } - runMainMenuSelection(); +void xCountTheTime( int temperatureMarginRange, boolean bMaximumOfUpDown ) { + unsigned long now = millis(); - break; - } - case eMenuType_StartFromStage: { - eStartFromStageMenuPosition = static_cast(rotaryEncoderVirtualPosition); + // Get current maximum sensed temperaure + double temperatureCount = 0; + if ( bMaximumOfUpDown ) { + float tup = upPT100.getCurrentTemperature(); + float tdown = downPT100.getCurrentTemperature(); + if (tup > tdown) { + temperatureCount = tdown; + } + else { + temperatureCount = tup; + } + } else { + temperatureCount = basePT100.getCurrentTemperature(); + } - repaint = displayStageMenu( &lcd, eStartFromStageMenuPosition, repaint ); + // Ignote time ticks if temperature is not within the acceptable margin for this stage + unsigned long elapsedTime = now - clockLastUpdate; + if ( temperatureCount < (cookTemperature - temperatureMarginRange) ) { + clockIgnore += elapsedTime; + } - if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) { - eStartFromStageMenuSelection = eStartFromStageMenuPosition; - } + // Calculate the remaining time on the clock + clockCounter = cookTime * 1000 - (elapsedTime - clockIgnore); - runStartFromStageSelection(); + // Don't let clock get bellow 0 + if ( clockCounter < 0 ) { + clockCounter = 0; + } - break; - } - case eMenuType_BeerProfile: { - eBeerProfileMenuPosition = static_cast(rotaryEncoderVirtualPosition); + clockLastUpdate = now; - repaint = displayBeerProfileMenu( &lcd, eBeerProfileMenuPosition, repaint ); +#ifdef DEBUG_OFF + debugPrintFunction("xCountTheTime"); + debugPrintVar("millis()", now); + debugPrintVar("cookTime", cookTime); + debugPrintVar("clockStartTime", clockStartTime); + debugPrintVar("clockIgnore", clockIgnore); + debugPrintVar("clockCounter", clockCounter); +#endif +} - if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) { - eBeerProfileMenuSelection = eBeerProfileMenuPosition; - } +bool isTimeLeft() { + if ( clockCounter > 0 ) { + return true; + } + return false; +} - runBeerProfileSelection(); +//HEATING_ELEMENT_MAX_WATTAGE / HEATING_ELEMENT_AC_FREQUENCY_HZ +double ulWattToWindowTime( double ulAppliedWatts ) { + double ulPulsesRequired = ulAppliedWatts / dWattPerPulse; + return (double)iWindowSize / 1000.0 * ulPulsesRequired * 1000.0 / HEATING_ELEMENT_AC_FREQUENCY_HZ; +} - break; - } - case eMenuType_Stage: { - eStageMenuPosition = static_cast(rotaryEncoderVirtualPosition); +bool xRegulateTemperature( boolean bMaximumOfUpDown ) { + double difference = 0; + bool overTemperature = false; + double wattage = 0.0; - repaint = displayStageMenu( &lcd, eStageMenuPosition, repaint ); + float tup = upPT100.getCurrentTemperature(); + float tdown = downPT100.getCurrentTemperature(); + float tbase = basePT100.getCurrentTemperature(); - if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) { - eStageMenuSelection = eStageMenuPosition; - } + if ( bMaximumOfUpDown ) { + if (tup > tdown) { + difference = cookTemperature - tup; + } + else { + difference = cookTemperature - tdown; + } - runStageSelection(); + if (tbase > cookTemperature && (tbase >= (PUMP_TEMPERATURE_MAX_OPERATION - 2.0) || difference >= 5.0)) { + difference = cookTemperature - tbase; + } - break; - } - case eMenuType_Malt: { - eMaltMenuPosition = static_cast(rotaryEncoderVirtualPosition); + if ( (tbase < cookTemperature) && (difference < (cookTemperature - tbase)) ) { + difference = cookTemperature - tbase; + } + } else { + difference = cookTemperature - tbase; + } - repaint = displayMaltMenu( &lcd, eMaltMenuPosition, repaint ); + // Deviation between the cook temperature set and the cook temperature measured + if ( difference < 0.0 ) { + difference = difference * (-1.0); + overTemperature = true; + } - if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) { - eMaltMenuSelection = eMaltMenuPosition; + // Calculate applied wattage, based on the distance from the target temperature + if ( overTemperature ) { + // turn it off + wattage = 0.0; + } else { + //if(difference <= 0.1) { + // turn it off + // wattage = 0.0; + //} else { + if (difference <= 0.5) { + // pulse lightly at 500 watt + if (cookTemperature > 99.0) { + wattage = 2000.0; + } + else { + if (cookTemperature > 70.0) { + wattage = 1000.0; + } + else { + wattage = 500.0; } - - runMaltSelection(); - - break; } - case eMenuType_Settings: { - eSettingsMenuPosition = static_cast(rotaryEncoderVirtualPosition); - - repaint = displaySettingsMenu( &lcd, eSettingsMenuPosition, repaint ); + } else { + if (difference <= 1.0) { + // pulse moderately at 1000 watt + if (cookTemperature > 99.0) { + wattage = 2000.0; + } + else { + wattage = 1000.0; + } - if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) { - eSettingsMenuSelection = eSettingsMenuPosition; + } else { + if (difference <= 3.0) { + // pulse hardly at 2000 watt + wattage = 2000.0; + } else { + //pulse constantly at HEATING_ELEMENT_MAX_WATTAGE watt + wattage = HEATING_ELEMENT_MAX_WATTAGE; } + } + } + //} + } - runSettingsSelection(); + // Update the recorded time for the begining of the window, if the previous window has passed + while ((millis() - windowStartTime) > iWindowSize) { // Check if it's time to vary the pulse width modulation and if so do it by shifting the "Relay in ON" Window + windowStartTime += iWindowSize; + } - break; - } + // Apply wattage to the element at the right time + if ( ulWattToWindowTime( wattage ) > (millis() - windowStartTime) ) { + digitalWrite(HEATING_ELEMENT_OUTPUT_PIN, HIGH); + bStatusElement = true; + } else { + digitalWrite(HEATING_ELEMENT_OUTPUT_PIN, LOW); + bStatusElement = false; } #ifdef DEBUG_OFF - if (debug_go) { - debugPrintVar("repaint", repaint); - } + //debugPrintFunction("xRegulateTemperature"); + debugPrintVar("difference", difference); + //debugPrintVar("overTemperature", overTemperature); + debugPrintVar("wattage", wattage); + //debugPrintVar("ulWattToWindowTime( wattage )", ulWattToWindowTime( wattage ) ); + //debugPrintVar("millis()", millis()); + //debugPrintVar("windowStartTime", windowStartTime); + //debugPrintVar("test", ulWattToWindowTime( wattage ) > (millis() - windowStartTime) ); #endif } -void runSettingsSelection() { - switch (eSettingsMenuSelection) { - case eSettingsMenu_Pump: { - // Stuff - if ( xSetGenericValue( iPumpSpeed ? 0 : 1, 0, 1, "pump", "bool" ) ) { - iPumpSpeed = PUMP_SPEED_MAX_MOSFET; - } else { - iPumpSpeed = PUMP_SPEED_STOP_MOSFET; - } - analogWrite(PUMP_PIN, iPumpSpeed); - - backToStatus(); - - break; - } - case eSettingsMenu_PT100_Element: { - // Stuff - - backToStatus(); - - break; - } - case eSettingsMenu_PT100_Up: { - // Stuff - - backToStatus(); - - break; - } - case eSettingsMenu_PT100_Down: { - // Stuff +void xPurgePump() { + for (int i = 0; i < 2; i++) { + analogWrite(PUMP_PIN, PUMP_SPEED_MAX_MOSFET); // analogWrite values from 0 to 255 + delay(1000); + analogWrite(PUMP_PIN, PUMP_SPEED_STOP_MOSFET); // analogWrite values from 0 to 255 + delay(1500); + } +} - backToStatus(); +bool xRegulatePumpSpeed() { + // analogWrite(PUMP_PIN, iPumpSpeed); // analogWrite values from 0 to 255 - break; - } - case eSettingsMenu_Back: { - eMenuType = eMenuType_Main; - repaint = true; + if (basePT100.getCurrentTemperature() > PUMP_TEMPERATURE_MAX_OPERATION) { + analogWrite(PUMP_PIN, PUMP_SPEED_STOP_MOSFET); // analogWrite values from 0 to 255 - // reset operation state | INPUT : eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep - //xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenuPosition, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 ); - xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMainMenu._position, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 ); + basePT100.setPumpStatus( false ); + upPT100.setPumpStatus( false ); + downPT100.setPumpStatus( false ); + } + else { + analogWrite(PUMP_PIN, iPumpSpeed); // analogWrite values from 0 to 255 - break; - } - default: { - } + basePT100.setPumpStatus( true ); + upPT100.setPumpStatus( true ); + downPT100.setPumpStatus( true ); } +} - eSettingsMenuSelection = eSettingsMenu_NULL; +void xWarnClockEnded() { + sing(MELODY_SUPER_MARIO_START, PIEZO_PIN); } -void runMaltSelection() { - switch (eMaltMenuSelection) { - case eMaltMenu_CastleMalting_Chteau_Pilsen_2RS: { - // Stuff +void xWarnCookEnded() { + sing(MELODY_UNDERWORLD_SHORT, PIEZO_PIN); +} - backToStatus(); +void xPrepareForStage( int stageTime, int stageTemperature, int stagePumpSpeed, eCookingStages stage ) { +#ifdef DEBUG_OFF + debugPrintFunction("xPrepareForStage"); + debugPrintVar("cookingStage", stage); +#endif - break; - } - case eMaltMenu_CastleMalting_Wheat_Blanc: { - // Stuff - - backToStatus(); - - break; - } - case eMaltMenu_Back: { - eMenuType = eMenuType_Main; - repaint = true; - - // reset operation state | INPUT : eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep - //xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenuPosition, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 ); - xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMainMenu._position, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 ); - - break; - } - default: { - } - } + // Reset the clock + unsigned long now = millis(); + clockStartTime = now; + clockLastUpdate = now; + clockIgnore = 0; - eMaltMenuSelection = eMaltMenu_NULL; + iPumpSpeed = stagePumpSpeed; // Set the pump speed + cookingStage = stage; // Set Stage + cookTime = stageTime; // Set the clock + cookTemperature = stageTemperature; // Set the target temperature } -void runStageSelection() { - switch (eStageMenuSelection) { - case eStageMenu_Startpoint: { - startpointTime = getTimer( startpointTime ); +void xSetupStage(eCookingStages nextStage) { +#ifdef DEBUG_OFF + debugPrintFunction("xSetupStage"); + debugPrintVar("cookingStage", nextStage); +#endif - startpointTemperature = xSetGenericValue( startpointTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" ); + // Operate the machine according to the current mode + switch (nextStage) { + case eCookingStage_Startpoint: { + switch (beerProfile) { + case eBeerProfile_Trigo: { + float wheatAmount = 0.05 * ((float) finalYield); + float pilsnerAmount = 0.2 * ((float) finalYield); + String say = "Cruch "; + say += String(wheatAmount); + say += String("Kg of Wheat and "); + say += String(pilsnerAmount); + say += String("Kg of Pilsner Malt into a pot."); - backToStatus(); + xWaitForAction("Malt", say); + repaint = true; + break; + } + case eBeerProfile_IPA: { + float caramelAmount = 0.013157895 * ((float) finalYield); + float wheatAmount = 0.060526316 * ((float) finalYield); + float pilsnerAmount = 0.115789474 * ((float) finalYield); + float munichAmount = 0.028947368 * ((float) finalYield); + String say = "Cruch "; + say += String(caramelAmount); + say += String("Kg of Caramel 120, "); + say += String(wheatAmount); + say += String("Kg of Wheat, "); + say += String(pilsnerAmount); + say += String("Kg of Pilsner, "); + say += String(munichAmount); + say += String("Kg of Munich into a pot."); - break; - } - case eStageMenu_BetaGlucanase: { - betaGlucanaseTime = getTimer( betaGlucanaseTime ); + xWaitForAction("Malt", say); + repaint = true; + break; + } + default: { - betaGlucanaseTemperature = xSetGenericValue( betaGlucanaseTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" ); + } + } - backToStatus(); + // Make sure there is water + xWaitForAction("Water", "Make sure there is water in the machine before start cooking."); + repaint = true; + xPrepareForStage( startpointTime, startpointTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Startpoint ); break; } - case eStageMenu_Debranching: { - debranchingTime = getTimer( debranchingTime ); - - debranchingTemperature = xSetGenericValue( debranchingTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" ); + case eCookingStage_BetaGlucanase: { + switch (beerProfile) { + case eBeerProfile_Trigo: { + float wheatAmount = 0.05 * ((float) finalYield); + float pilsnerAmount = 0.2 * ((float) finalYield); + String say = "Put "; + say += String(wheatAmount); + say += String("Kg of Wheat and "); + say += String(pilsnerAmount); + say += String("Kg of Pilsner Malt in."); - backToStatus(); + xWaitForAction("Malt", say); + repaint = true; + break; + } + case eBeerProfile_IPA: { + float caramelAmount = 0.013157895 * ((float) finalYield); + float wheatAmount = 0.060526316 * ((float) finalYield); + float pilsnerAmount = 0.115789474 * ((float) finalYield); + float munichAmount = 0.028947368 * ((float) finalYield); + String say = "Cruch "; + say += String(caramelAmount); + say += String("Kg of Caramel 120, "); + say += String(wheatAmount); + say += String("Kg of Wheat, "); + say += String(pilsnerAmount); + say += String("Kg of Pilsner, "); + say += String(munichAmount); + say += String("Kg of Munich into a pot."); + xWaitForAction("Malt", say); + repaint = true; + break; + } + default: {} + } + xPrepareForStage( betaGlucanaseTime, betaGlucanaseTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_BetaGlucanase ); break; } - case eStageMenu_Proteolytic: { - proteolyticTime = getTimer( proteolyticTime ); - - proteolyticTemperature = xSetGenericValue( proteolyticTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" ); - - backToStatus(); - + case eCookingStage_Debranching: { + xPrepareForStage( debranchingTime, debranchingTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Debranching ); break; } - case eStageMenu_BetaAmylase: { - betaAmylaseTime = getTimer( betaAmylaseTime ); - - betaAmylaseTemperature = xSetGenericValue( betaAmylaseTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" ); - - backToStatus(); - + case eCookingStage_Proteolytic: { + xPrepareForStage( proteolyticTime, proteolyticTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Proteolytic ); break; } - case eStageMenu_AlphaAmylase: { - alphaAmylaseTime = getTimer( alphaAmylaseTime ); - - alphaAmylaseTemperature = xSetGenericValue( alphaAmylaseTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" ); - - backToStatus(); - + case eCookingStage_BetaAmylase: { + xPrepareForStage( betaAmylaseTime, betaAmylaseTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_BetaAmylase ); break; } - case eStageMenu_Mashout: { - mashoutTime = getTimer( mashoutTime ); - - mashoutTemperature = xSetGenericValue( mashoutTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" ); - - backToStatus(); - + case eCookingStage_AlphaAmylase: { + xPrepareForStage( alphaAmylaseTime, alphaAmylaseTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_AlphaAmylase ); break; } - case eStageMenu_Recirculation: { - recirculationTime = getTimer( recirculationTime ); - - recirculationTemperature = xSetGenericValue( recirculationTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" ); - - backToStatus(); - + case eCookingStage_Mashout: { + xPrepareForStage( mashoutTime, mashoutTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Mashout ); break; } - case eStageMenu_Sparge: { - spargeTime = getTimer( spargeTime ); - - spargeTemperature = xSetGenericValue( spargeTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" ); - - backToStatus(); - + case eCookingStage_Recirculation: { + xWaitForAction("Sparge Water", "Start heating your sparge water."); + repaint = true; + xPrepareForStage( recirculationTime, recirculationTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Recirculation ); break; } - case eStageMenu_Boil: { - boilTime = getTimer( boilTime ); - - boilTemperature = xSetGenericValue( boilTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" ); - - backToStatus(); - + case eCookingStage_Sparge: { + xWaitForAction("Sparge Water", "Start pouring the sparge water."); + repaint = true; + xPrepareForStage( spargeTime, spargeTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Sparge ); break; } - case eStageMenu_Cooling: { - coolingTime = getTimer( coolingTime ); - - coolingTemperature = xSetGenericValue( coolingTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" ); + case eCookingStage_Boil: { + switch (beerProfile) { + case eBeerProfile_Trigo: { + String say = "Get "; - backToStatus(); + float hopAmount = 0.8 * ((float) finalYield); + say += String(hopAmount); - break; - } - case eStageMenu_Back: { - eMenuType = eMenuType_Main; - repaint = true; + say += String("g of Magnum 9.4\% and Styrian Golding 5\% ready."); - // reset operation state | INPUT : eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep - //xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenuPosition, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 ); - xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMainMenu._position, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 ); + xWaitForAction("Hops", say); - break; - } - default: { - } - } + break; + } + case eBeerProfile_IPA: { + String say = "Get "; - eStageMenuSelection = eStageMenu_NULL; -} + float hopAmount = 0.8 * ((float) finalYield); + say += String(hopAmount); -void runBeerProfileSelection() { - switch (eBeerProfileMenuSelection) { - case eBeerProfileMenu_Basic: { - beerProfile = eBeerProfile_Basic; - - startpointTime = PROFILE_BASIC_STARTPOINT_TIME; - betaGlucanaseTime = PROFILE_BASIC_BETAGLUCANASE_TIME; - debranchingTime = PROFILE_BASIC_DEBRANCHING_TIME; - proteolyticTime = PROFILE_BASIC_PROTEOLYTIC_TIME; - betaAmylaseTime = PROFILE_BASIC_BETAAMYLASE_TIME; - alphaAmylaseTime = PROFILE_BASIC_ALPHAAMYLASE_TIME; - mashoutTime = PROFILE_BASIC_MASHOUT_TIME; - recirculationTime = PROFILE_BASIC_RECIRCULATION_TIME; - spargeTime = PROFILE_BASIC_SPARGE_TIME; - boilTime = PROFILE_BASIC_BOIL_TIME; - coolingTime = PROFILE_BASIC_COOLING_TIME; - - startpointTemperature = PROFILE_BASIC_STARTPOINT_TEMPERATURE; - betaGlucanaseTemperature = PROFILE_BASIC_BETAGLUCANASE_TEMPERATURE; - debranchingTemperature = PROFILE_BASIC_DEBRANCHING_TEMPERATURE; - proteolyticTemperature = PROFILE_BASIC_PROTEOLYTIC_TEMPERATURE; - betaAmylaseTemperature = PROFILE_BASIC_BETAAMYLASE_TEMPERATURE; - alphaAmylaseTemperature = PROFILE_BASIC_ALPHAAMYLASE_TEMPERATURE; - mashoutTemperature = PROFILE_BASIC_MASHOUT_TEMPERATURE; - recirculationTemperature = PROFILE_BASIC_RECIRCULATION_TEMPERATURE; - spargeTemperature = PROFILE_BASIC_SPARGE_TEMPERATURE; - boilTemperature = PROFILE_BASIC_BOIL_TEMPERATURE; - coolingTemperature = PROFILE_BASIC_COOLING_TEMPERATURE; + say += String("g of Chinook, Cascade and Styrian Golding ready."); - backToStatus(); + xWaitForAction("Hops", say); - break; - } - case eBeerProfileMenu_Trigo: { - beerProfile = eBeerProfile_Trigo; - - startpointTime = PROFILE_TRIGO_STARTPOINT_TIME; - betaGlucanaseTime = PROFILE_TRIGO_BETAGLUCANASE_TIME; - debranchingTime = PROFILE_TRIGO_DEBRANCHING_TIME; - proteolyticTime = PROFILE_TRIGO_PROTEOLYTIC_TIME; - betaAmylaseTime = PROFILE_TRIGO_BETAAMYLASE_TIME; - alphaAmylaseTime = PROFILE_TRIGO_ALPHAAMYLASE_TIME; - mashoutTime = PROFILE_TRIGO_MASHOUT_TIME; - recirculationTime = PROFILE_TRIGO_RECIRCULATION_TIME; - spargeTime = PROFILE_TRIGO_SPARGE_TIME; - boilTime = PROFILE_TRIGO_BOIL_TIME; - coolingTime = PROFILE_TRIGO_COOLING_TIME; - - startpointTemperature = PROFILE_TRIGO_STARTPOINT_TEMPERATURE; - betaGlucanaseTemperature = PROFILE_TRIGO_BETAGLUCANASE_TEMPERATURE; - debranchingTemperature = PROFILE_TRIGO_DEBRANCHING_TEMPERATURE; - proteolyticTemperature = PROFILE_TRIGO_PROTEOLYTIC_TEMPERATURE; - betaAmylaseTemperature = PROFILE_TRIGO_BETAAMYLASE_TEMPERATURE; - alphaAmylaseTemperature = PROFILE_TRIGO_ALPHAAMYLASE_TEMPERATURE; - mashoutTemperature = PROFILE_TRIGO_MASHOUT_TEMPERATURE; - recirculationTemperature = PROFILE_TRIGO_RECIRCULATION_TEMPERATURE; - spargeTemperature = PROFILE_TRIGO_SPARGE_TEMPERATURE; - boilTemperature = PROFILE_TRIGO_BOIL_TEMPERATURE; - coolingTemperature = PROFILE_TRIGO_COOLING_TEMPERATURE; + break; + } + default: { + xWaitForAction("Hops", "Add the hops in the right order, at the right time."); - backToStatus(); + } + } - break; - } - case eBeerProfileMenu_IPA: { - beerProfile = eBeerProfile_IPA; - - startpointTime = PROFILE_IPA_STARTPOINT_TIME; - betaGlucanaseTime = PROFILE_IPA_BETAGLUCANASE_TIME; - debranchingTime = PROFILE_IPA_DEBRANCHING_TIME; - proteolyticTime = PROFILE_IPA_PROTEOLYTIC_TIME; - betaAmylaseTime = PROFILE_IPA_BETAAMYLASE_TIME; - alphaAmylaseTime = PROFILE_IPA_ALPHAAMYLASE_TIME; - mashoutTime = PROFILE_IPA_MASHOUT_TIME; - recirculationTime = PROFILE_IPA_RECIRCULATION_TIME; - spargeTime = PROFILE_IPA_SPARGE_TIME; - boilTime = PROFILE_IPA_BOIL_TIME; - coolingTime = PROFILE_IPA_COOLING_TIME; - - startpointTemperature = PROFILE_IPA_STARTPOINT_TEMPERATURE; - betaGlucanaseTemperature = PROFILE_IPA_BETAGLUCANASE_TEMPERATURE; - debranchingTemperature = PROFILE_IPA_DEBRANCHING_TEMPERATURE; - proteolyticTemperature = PROFILE_IPA_PROTEOLYTIC_TEMPERATURE; - betaAmylaseTemperature = PROFILE_IPA_BETAAMYLASE_TEMPERATURE; - alphaAmylaseTemperature = PROFILE_IPA_ALPHAAMYLASE_TEMPERATURE; - mashoutTemperature = PROFILE_IPA_MASHOUT_TEMPERATURE; - recirculationTemperature = PROFILE_IPA_RECIRCULATION_TEMPERATURE; - spargeTemperature = PROFILE_IPA_SPARGE_TEMPERATURE; - boilTemperature = PROFILE_IPA_BOIL_TEMPERATURE; - coolingTemperature = PROFILE_IPA_COOLING_TEMPERATURE; + repaint = true; - backToStatus(); + // A basic operation for a basic stage + xPrepareForStage( boilTime, boilTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Boil ); break; } - case eBeerProfileMenu_Belga: { - beerProfile = eBeerProfile_Belga; - - startpointTime = PROFILE_BELGA_STARTPOINT_TIME; - betaGlucanaseTime = PROFILE_BELGA_BETAGLUCANASE_TIME; - debranchingTime = PROFILE_BELGA_DEBRANCHING_TIME; - proteolyticTime = PROFILE_BELGA_PROTEOLYTIC_TIME; - betaAmylaseTime = PROFILE_BELGA_BETAAMYLASE_TIME; - alphaAmylaseTime = PROFILE_BELGA_ALPHAAMYLASE_TIME; - mashoutTime = PROFILE_BELGA_MASHOUT_TIME; - recirculationTime = PROFILE_BELGA_RECIRCULATION_TIME; - spargeTime = PROFILE_BELGA_SPARGE_TIME; - boilTime = PROFILE_BELGA_BOIL_TIME; - coolingTime = PROFILE_BELGA_COOLING_TIME; - - startpointTemperature = PROFILE_BELGA_STARTPOINT_TEMPERATURE; - betaGlucanaseTemperature = PROFILE_BELGA_BETAGLUCANASE_TEMPERATURE; - debranchingTemperature = PROFILE_BELGA_DEBRANCHING_TEMPERATURE; - proteolyticTemperature = PROFILE_BELGA_PROTEOLYTIC_TEMPERATURE; - betaAmylaseTemperature = PROFILE_BELGA_BETAAMYLASE_TEMPERATURE; - alphaAmylaseTemperature = PROFILE_BELGA_ALPHAAMYLASE_TEMPERATURE; - mashoutTemperature = PROFILE_BELGA_MASHOUT_TEMPERATURE; - recirculationTemperature = PROFILE_BELGA_RECIRCULATION_TEMPERATURE; - spargeTemperature = PROFILE_BELGA_SPARGE_TEMPERATURE; - boilTemperature = PROFILE_BELGA_BOIL_TEMPERATURE; - coolingTemperature = PROFILE_BELGA_COOLING_TEMPERATURE; + case eCookingStage_Cooling: { + // Make sure there is water + xWaitForAction("Coil", "Add the coil and connect it to the main water supply."); - backToStatus(); + repaint = true; + + // A basic operation for a basic stage + xPrepareForStage( coolingTime, coolingTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Cooling ); break; } - case eBeerProfileMenu_Red: { - beerProfile = eBeerProfile_Red; - - startpointTime = PROFILE_RED_STARTPOINT_TIME; - betaGlucanaseTime = PROFILE_RED_BETAGLUCANASE_TIME; - debranchingTime = PROFILE_RED_DEBRANCHING_TIME; - proteolyticTime = PROFILE_RED_PROTEOLYTIC_TIME; - betaAmylaseTime = PROFILE_RED_BETAAMYLASE_TIME; - alphaAmylaseTime = PROFILE_RED_ALPHAAMYLASE_TIME; - mashoutTime = PROFILE_RED_MASHOUT_TIME; - recirculationTime = PROFILE_RED_RECIRCULATION_TIME; - spargeTime = PROFILE_RED_SPARGE_TIME; - boilTime = PROFILE_RED_BOIL_TIME; - coolingTime = PROFILE_RED_COOLING_TIME; - - startpointTemperature = PROFILE_RED_STARTPOINT_TEMPERATURE; - betaGlucanaseTemperature = PROFILE_RED_BETAGLUCANASE_TEMPERATURE; - debranchingTemperature = PROFILE_RED_DEBRANCHING_TEMPERATURE; - proteolyticTemperature = PROFILE_RED_PROTEOLYTIC_TEMPERATURE; - betaAmylaseTemperature = PROFILE_RED_BETAAMYLASE_TEMPERATURE; - alphaAmylaseTemperature = PROFILE_RED_ALPHAAMYLASE_TEMPERATURE; - mashoutTemperature = PROFILE_RED_MASHOUT_TEMPERATURE; - recirculationTemperature = PROFILE_RED_RECIRCULATION_TEMPERATURE; - spargeTemperature = PROFILE_RED_SPARGE_TEMPERATURE; - boilTemperature = PROFILE_RED_BOIL_TEMPERATURE; - coolingTemperature = PROFILE_RED_COOLING_TEMPERATURE; + case eCookingStage_Clean: { + // Make sure there is water + xWaitForAction("Water", "Add 13 liters."); - backToStatus(); + // Make sure there is water + xWaitForAction("Star San HB", "Add 0.89oz/26ml."); - break; - } - case eBeerProfileMenu_APA: { - beerProfile = eBeerProfile_APA; - - startpointTime = PROFILE_APA_STARTPOINT_TIME; - betaGlucanaseTime = PROFILE_APA_BETAGLUCANASE_TIME; - debranchingTime = PROFILE_APA_DEBRANCHING_TIME; - proteolyticTime = PROFILE_APA_PROTEOLYTIC_TIME; - betaAmylaseTime = PROFILE_APA_BETAAMYLASE_TIME; - alphaAmylaseTime = PROFILE_APA_ALPHAAMYLASE_TIME; - mashoutTime = PROFILE_APA_MASHOUT_TIME; - recirculationTime = PROFILE_APA_RECIRCULATION_TIME; - spargeTime = PROFILE_APA_SPARGE_TIME; - boilTime = PROFILE_APA_BOIL_TIME; - coolingTime = PROFILE_APA_COOLING_TIME; - - startpointTemperature = PROFILE_APA_STARTPOINT_TEMPERATURE; - betaGlucanaseTemperature = PROFILE_APA_BETAGLUCANASE_TEMPERATURE; - debranchingTemperature = PROFILE_APA_DEBRANCHING_TEMPERATURE; - proteolyticTemperature = PROFILE_APA_PROTEOLYTIC_TEMPERATURE; - betaAmylaseTemperature = PROFILE_APA_BETAAMYLASE_TEMPERATURE; - alphaAmylaseTemperature = PROFILE_APA_ALPHAAMYLASE_TEMPERATURE; - mashoutTemperature = PROFILE_APA_MASHOUT_TEMPERATURE; - recirculationTemperature = PROFILE_APA_RECIRCULATION_TEMPERATURE; - spargeTemperature = PROFILE_APA_SPARGE_TEMPERATURE; - boilTemperature = PROFILE_APA_BOIL_TEMPERATURE; - coolingTemperature = PROFILE_APA_COOLING_TEMPERATURE; + repaint = true; - backToStatus(); + // A basic operation for a basic stage + xPrepareForStage( cleaningTime, cleaningTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Clean ); break; } - case eBeerProfileMenu_Custom: { - beerProfile = eBeerProfile_Custom; - - startpointTime = PROFILE_CUSTOM_STARTPOINT_TIME; - betaGlucanaseTime = PROFILE_CUSTOM_BETAGLUCANASE_TIME; - debranchingTime = PROFILE_CUSTOM_DEBRANCHING_TIME; - proteolyticTime = PROFILE_CUSTOM_PROTEOLYTIC_TIME; - betaAmylaseTime = PROFILE_CUSTOM_BETAAMYLASE_TIME; - alphaAmylaseTime = PROFILE_CUSTOM_ALPHAAMYLASE_TIME; - mashoutTime = PROFILE_CUSTOM_MASHOUT_TIME; - recirculationTime = PROFILE_CUSTOM_RECIRCULATION_TIME; - spargeTime = PROFILE_CUSTOM_SPARGE_TIME; - boilTime = PROFILE_CUSTOM_BOIL_TIME; - coolingTime = PROFILE_CUSTOM_COOLING_TIME; - - startpointTemperature = PROFILE_CUSTOM_STARTPOINT_TEMPERATURE; - betaGlucanaseTemperature = PROFILE_CUSTOM_BETAGLUCANASE_TEMPERATURE; - debranchingTemperature = PROFILE_CUSTOM_DEBRANCHING_TEMPERATURE; - proteolyticTemperature = PROFILE_CUSTOM_PROTEOLYTIC_TEMPERATURE; - betaAmylaseTemperature = PROFILE_CUSTOM_BETAAMYLASE_TEMPERATURE; - alphaAmylaseTemperature = PROFILE_CUSTOM_ALPHAAMYLASE_TEMPERATURE; - mashoutTemperature = PROFILE_CUSTOM_MASHOUT_TEMPERATURE; - recirculationTemperature = PROFILE_CUSTOM_RECIRCULATION_TEMPERATURE; - spargeTemperature = PROFILE_CUSTOM_SPARGE_TEMPERATURE; - boilTemperature = PROFILE_CUSTOM_BOIL_TEMPERATURE; - coolingTemperature = PROFILE_CUSTOM_COOLING_TEMPERATURE; + case eCookingStage_Purge: { + // A basic operation for a basic stage + xPrepareForStage( 0, 0, PUMP_SPEED_MAX_MOSFET, eCookingStage_Purge ); - backToStatus(); + xRegulatePumpSpeed(); break; } - case eBeerProfileMenu_Back: { - eMenuType = eMenuType_Main; - repaint = true; - - // reset operation state | INPUT : eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep - //xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenuPosition, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 ); - xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMainMenu._position, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 ); + case eCookingStage_Done: { + // A basic operation for a basic stage + xPrepareForStage( 0, 0, PUMP_SPEED_STOP_MOSFET, eCookingStage_Done ); break; } - default: { - } } - - eBeerProfileMenuSelection = eBeerProfileMenu_NULL; } -void xStartStage( unsigned long *stageTime, int *stageTemperature, eCookingStages nextStage, bool bPurgePump, bool bSetFinalYield, bool bSetTime, bool bSetTemperature ) { - xSafeHardwarePowerOff(); // Stop anything that might be still going on +void xTransitionIntoStage(eCookingStages nextStage) { + // Turn off all hardware that can damage itself if the machine is not cooking + xSafeHardwarePowerOff(); - if (bSetFinalYield) { - finalYield = xSetFinalYield( finalYield ); + // Warn the user a stage has ended + xWarnClockEnded(); + + // Reset global stage variables + xSetupStage( nextStage ); +} + +void xBasicStageOperation( int iStageTime, int iStageTemperature, int iStageTemperatureRange, eCookingStages nextStage, boolean bMaximumOfUpDown ) { + + // Account for time spent at the target temperature | Input 1: range in ºC within which the target temperature is considered to be reached +#ifdef DEBUG_OFF + xCountTheTime( iStageTemperatureRange, false ); +#else + xCountTheTime( iStageTemperatureRange, bMaximumOfUpDown ); +#endif + + if ( isTimeLeft() ) { + // Do temperature control + xRegulateTemperature( bMaximumOfUpDown ); + + // Do flow control + xRegulatePumpSpeed(); + + } else { +#ifdef DEBUG_OFF + debugPrintFunction("xBasicStageOperation"); + debugPrintVar("clockCounter", clockCounter); +#endif + + // Continue to the next stage, there is nothing to do, in this stage + xTransitionIntoStage( nextStage ); + return; } - if (bSetTime) { - (*stageTime) = getTimer( clockCounter / 1000, (*stageTime) ); + + return; +} + +void xManageMachineSystems() { + +#ifdef DEBUG + Serial.print(millis()); + Serial.print(","); + if (cooking) { + Serial.print("1"); } - if (bSetTemperature) { - (*stageTemperature) = xSetTemperature( (*stageTemperature) ); + else { + Serial.print("0"); } - if (bPurgePump) { - xPurgePump(); + Serial.print(","); + Serial.print(cookTemperature); + Serial.print(","); + if (bStatusElement) { + Serial.print("1"); + } + else { + Serial.print("0"); } + Serial.print(","); +#endif - startBrewing(); - xSetupStage( nextStage ); - backToStatus(); -} + // Measure temperature, for effect + basePT100.measure(false); + upPT100.measure(false); + downPT100.measure(true); -void xStartStageHeadless( eCookingStages nextStage, bool bPurgePump ) { - xStartStage( NULL, NULL, nextStage, bPurgePump, false, false, false ); -} + // If cooking is done, return (this is a nice place to double check safety and ensure the cooking parts aren't on. + if (!cooking) { + xSafeHardwarePowerOff(); -void xStartStageInteractive( unsigned long *stageTime, int *stageTemperature, eCookingStages nextStage ) { - xStartStage( stageTime, stageTemperature, nextStage, true, true, true, true ); -} + return; + } -void runStartFromStageSelection() { - switch (eStartFromStageMenuSelection) { - case eStageMenu_Startpoint: { - xStartStageInteractive( &startpointTime, &startpointTemperature, eCookingStage_Startpoint ); + // Operate the machine according to the current mode + switch (cookingStage) { + case eCookingStage_Startpoint: { + xBasicStageOperation( startpointTime, startpointTemperature, 0, eCookingStage_BetaGlucanase, false); break; } - case eStageMenu_BetaGlucanase: { - xStartStageInteractive( &betaGlucanaseTime, &betaGlucanaseTemperature, eCookingStage_BetaGlucanase ); + case eCookingStage_BetaGlucanase: { + xBasicStageOperation( betaGlucanaseTime, betaGlucanaseTemperature, 3, eCookingStage_Debranching, true ); break; } - case eStageMenu_Debranching: { - xStartStageInteractive( &debranchingTime, &debranchingTemperature, eCookingStage_Debranching ); + case eCookingStage_Debranching: { + xBasicStageOperation( debranchingTime, debranchingTemperature, 3, eCookingStage_Proteolytic, true ); break; } - case eStageMenu_Proteolytic: { - xStartStageInteractive( &proteolyticTime, &proteolyticTemperature, eCookingStage_Proteolytic ); + case eCookingStage_Proteolytic: { + xBasicStageOperation( proteolyticTime, proteolyticTemperature, 3, eCookingStage_BetaAmylase, true ); break; } - case eStageMenu_BetaAmylase: { - xStartStageInteractive( &betaAmylaseTime, &betaAmylaseTemperature, eCookingStage_BetaAmylase ); + case eCookingStage_BetaAmylase: { + xBasicStageOperation( betaAmylaseTime, betaAmylaseTemperature, 4, eCookingStage_AlphaAmylase, true ); break; } - case eStageMenu_AlphaAmylase: { - xStartStageInteractive( &alphaAmylaseTime, &alphaAmylaseTemperature, eCookingStage_AlphaAmylase ); + case eCookingStage_AlphaAmylase: { + xBasicStageOperation( alphaAmylaseTime, alphaAmylaseTemperature, 2, eCookingStage_Mashout, true ); break; } - case eStageMenu_Mashout: { - xStartStageInteractive( &mashoutTime, &mashoutTemperature, eCookingStage_Mashout ); + case eCookingStage_Mashout: { + xBasicStageOperation( mashoutTime, mashoutTemperature, 1, eCookingStage_Recirculation, true ); break; } - case eStageMenu_Recirculation: { - xStartStageInteractive( &recirculationTime, &recirculationTemperature, eCookingStage_Recirculation ); + case eCookingStage_Recirculation: { + xBasicStageOperation( recirculationTime, recirculationTemperature, 1, eCookingStage_Sparge, true ); break; } - case eStageMenu_Sparge: { - xStartStageInteractive( &spargeTime, &spargeTemperature, eCookingStage_Sparge ); + case eCookingStage_Sparge: { + xBasicStageOperation( spargeTime, spargeTemperature, 3, eCookingStage_Boil, false ); break; } - case eStageMenu_Boil: { - xStartStageInteractive( &boilTime, &boilTemperature, eCookingStage_Boil ); + case eCookingStage_Boil: { + xBasicStageOperation( boilTime, boilTemperature, 2, eCookingStage_Cooling, false ); break; } - case eStageMenu_Cooling: { - xStartStageInteractive( &coolingTime, &coolingTemperature, eCookingStage_Cooling ); + case eCookingStage_Cooling: { + xBasicStageOperation( coolingTime, coolingTemperature, 0, eCookingStage_Done, false ); break; } - case eStageMenu_Back: { - resetMenu( true ); + case eCookingStage_Clean: { + xBasicStageOperation( cleaningTime, cleaningTemperature, 0, eCookingStage_Done, false ); break; } - default: { - } + case eCookingStage_Purge: { + iPumpSpeed = PUMP_SPEED_MAX_MOSFET; + xRegulatePumpSpeed(); + break; + } + case eCookingStage_Done: { + stopBrewing(); // Update cooking state + repaint = true; // Ask for screen refresh + xWarnCookEnded(); // Warn the user that the cooking is done + break; + } + } +} + +// ##################################################### Menus ################################################################### + +// *************************** MENU BASE ********************************* +void runMenu() { +#ifdef DEBUG_OFF + boolean debug_go = repaint; + if (debug_go) { + debugPrintFunction("runMenu"); + debugPrintVar("repaint", repaint); + debugPrintVar("eMenuType", eMenuType); + debugPrintVar("rotaryEncoderVirtualPosition", rotaryEncoderVirtualPosition); + } +#endif + + switch (eMenuType) { + case eMenuType_Main: { + runMenuProcessor( &mdMainMenu ); + break; + } + case eMenuType_BeerProfile: { + runMenuProcessor( &mdBeerProfileMenu ); + break; + } + case eMenuType_Stage: { + runMenuProcessor( &mdStageMenu ); + break; + } + case eMenuType_Malt: { + runMenuProcessor( &mdMaltMenu ); + break; + } + case eMenuType_Settings: { + runMenuProcessor( &mdSettingsMenu ); + break; + } + case eMenuType_StartFromStage: { + runMenuProcessor( &mdStartFromStageMenu ); + break; + } + } + +#ifdef DEBUG_OFF + if (debug_go) { + debugPrintVar("repaint", repaint); } - eStartFromStageMenuSelection = eStageMenu_NULL; +#endif } +// ************************ MENU SELECTIONS ****************************** void runMainMenuSelection() { switch (mdMainMenu._selection) { //switch (eMainMenuSelection) { @@ -1032,7 +994,7 @@ void runMainMenuSelection() { case eMainMenu_GO_FROM_STAGE: { eMenuType = eMenuType_StartFromStage; repaint = true; - xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eBeerProfileMenuPosition, MENU_SIZE_PROFILES_MENU - 1, 1, 1, 0 ); + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdBeerProfileMenu._position, MENU_SIZE_PROFILES_MENU - 1, 1, 1, 0 ); break; } case eMainMenu_STOP: { @@ -1048,19 +1010,19 @@ void runMainMenuSelection() { case eMainMenu_BeerProfile: { eMenuType = eMenuType_BeerProfile; repaint = true; - xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eBeerProfileMenuPosition, MENU_SIZE_PROFILES_MENU - 1, 1, 1, 0 ); + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdBeerProfileMenu._position, MENU_SIZE_PROFILES_MENU - 1, 1, 1, 0 ); break; } case eMainMenu_Stage: { eMenuType = eMenuType_Stage; repaint = true; - xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eStageMenuPosition, MENU_SIZE_STAGE_MENU - 1, 1, 1, 0 ); + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdStageMenu._position, MENU_SIZE_STAGE_MENU - 1, 1, 1, 0 ); break; } case eMainMenu_Malt: { eMenuType = eMenuType_Malt; repaint = true; - xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMaltMenuPosition, MENU_SIZE_MALT_MENU - 1, 1, 1, 0 ); + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMaltMenu._position, MENU_SIZE_MALT_MENU - 1, 1, 1, 0 ); break; } case eMainMenu_Hops: { @@ -1078,7 +1040,7 @@ void runMainMenuSelection() { case eMainMenu_Settings: { eMenuType = eMenuType_Settings; repaint = true; - xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eSettingsMenuPosition, MENU_SIZE_SETTINGS_MENU - 1, 1, 1, 0 ); + xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdSettingsMenu._position, MENU_SIZE_SETTINGS_MENU - 1, 1, 1, 0 ); break; } case eMainMenu_Back: { @@ -1089,604 +1051,429 @@ void runMainMenuSelection() { } } mdMainMenu._selection = eMainMenu_NULL; - //eMainMenuSelection = eMainMenu_NULL; } -void xCountTheTime( int temperatureMarginRange, boolean bMaximumOfUpDown ) { - unsigned long now = millis(); - // Get current maximum sensed temperaure - double temperatureCount = 0; - if ( bMaximumOfUpDown ) { - float tup = upPT100.getCurrentTemperature(); - float tdown = downPT100.getCurrentTemperature(); - if (tup > tdown) { - temperatureCount = tdown; - } - else { - temperatureCount = tup; - } - } else { - temperatureCount = basePT100.getCurrentTemperature(); +void runStartFromStageSelection() { + switch (mdStartFromStageMenu._selection) { + case eStageMenu_Startpoint: { + xStartStageInteractive( &startpointTime, &startpointTemperature, eCookingStage_Startpoint ); + break; + } + case eStageMenu_BetaGlucanase: { + xStartStageInteractive( &betaGlucanaseTime, &betaGlucanaseTemperature, eCookingStage_BetaGlucanase ); + break; + } + case eStageMenu_Debranching: { + xStartStageInteractive( &debranchingTime, &debranchingTemperature, eCookingStage_Debranching ); + break; + } + case eStageMenu_Proteolytic: { + xStartStageInteractive( &proteolyticTime, &proteolyticTemperature, eCookingStage_Proteolytic ); + break; + } + case eStageMenu_BetaAmylase: { + xStartStageInteractive( &betaAmylaseTime, &betaAmylaseTemperature, eCookingStage_BetaAmylase ); + break; + } + case eStageMenu_AlphaAmylase: { + xStartStageInteractive( &alphaAmylaseTime, &alphaAmylaseTemperature, eCookingStage_AlphaAmylase ); + break; + } + case eStageMenu_Mashout: { + xStartStageInteractive( &mashoutTime, &mashoutTemperature, eCookingStage_Mashout ); + break; + } + case eStageMenu_Recirculation: { + xStartStageInteractive( &recirculationTime, &recirculationTemperature, eCookingStage_Recirculation ); + break; + } + case eStageMenu_Sparge: { + xStartStageInteractive( &spargeTime, &spargeTemperature, eCookingStage_Sparge ); + break; + } + case eStageMenu_Boil: { + xStartStageInteractive( &boilTime, &boilTemperature, eCookingStage_Boil ); + break; + } + case eStageMenu_Cooling: { + xStartStageInteractive( &coolingTime, &coolingTemperature, eCookingStage_Cooling ); + break; + } + case eStageMenu_Back: { + resetMenu( true ); + break; + } + default: { + } } + mdStartFromStageMenu._selection = eStageMenu_NULL; +} - // Ignote time ticks if temperature is not within the acceptable margin for this stage - unsigned long elapsedTime = now - clockLastUpdate; - if ( temperatureCount < (cookTemperature - temperatureMarginRange) ) { - clockIgnore += elapsedTime; - } - - // Calculate the remaining time on the clock - clockCounter = cookTime * 1000 - (elapsedTime - clockIgnore); - - // Don't let clock get bellow 0 - if ( clockCounter < 0 ) { - clockCounter = 0; - } - - clockLastUpdate = now; - -#ifdef DEBUG_OFF - debugPrintFunction("xCountTheTime"); - debugPrintVar("millis()", now); - debugPrintVar("cookTime", cookTime); - debugPrintVar("clockStartTime", clockStartTime); - debugPrintVar("clockIgnore", clockIgnore); - debugPrintVar("clockCounter", clockCounter); -#endif -} - -bool isTimeLeft() { - if ( clockCounter > 0 ) { - return true; +void runBeerProfileSelection() { + switch (mdBeerProfileMenu._selection) { + case eBeerProfileMenu_Basic: { + beerProfile = eBeerProfile_Basic; + startpointTime = PROFILE_BASIC_STARTPOINT_TIME; + betaGlucanaseTime = PROFILE_BASIC_BETAGLUCANASE_TIME; + debranchingTime = PROFILE_BASIC_DEBRANCHING_TIME; + proteolyticTime = PROFILE_BASIC_PROTEOLYTIC_TIME; + betaAmylaseTime = PROFILE_BASIC_BETAAMYLASE_TIME; + alphaAmylaseTime = PROFILE_BASIC_ALPHAAMYLASE_TIME; + mashoutTime = PROFILE_BASIC_MASHOUT_TIME; + recirculationTime = PROFILE_BASIC_RECIRCULATION_TIME; + spargeTime = PROFILE_BASIC_SPARGE_TIME; + boilTime = PROFILE_BASIC_BOIL_TIME; + coolingTime = PROFILE_BASIC_COOLING_TIME; + startpointTemperature = PROFILE_BASIC_STARTPOINT_TEMPERATURE; + betaGlucanaseTemperature = PROFILE_BASIC_BETAGLUCANASE_TEMPERATURE; + debranchingTemperature = PROFILE_BASIC_DEBRANCHING_TEMPERATURE; + proteolyticTemperature = PROFILE_BASIC_PROTEOLYTIC_TEMPERATURE; + betaAmylaseTemperature = PROFILE_BASIC_BETAAMYLASE_TEMPERATURE; + alphaAmylaseTemperature = PROFILE_BASIC_ALPHAAMYLASE_TEMPERATURE; + mashoutTemperature = PROFILE_BASIC_MASHOUT_TEMPERATURE; + recirculationTemperature = PROFILE_BASIC_RECIRCULATION_TEMPERATURE; + spargeTemperature = PROFILE_BASIC_SPARGE_TEMPERATURE; + boilTemperature = PROFILE_BASIC_BOIL_TEMPERATURE; + coolingTemperature = PROFILE_BASIC_COOLING_TEMPERATURE; + + backToStatus(); + break; + } + case eBeerProfileMenu_Trigo: { + beerProfile = eBeerProfile_Trigo; + startpointTime = PROFILE_TRIGO_STARTPOINT_TIME; + betaGlucanaseTime = PROFILE_TRIGO_BETAGLUCANASE_TIME; + debranchingTime = PROFILE_TRIGO_DEBRANCHING_TIME; + proteolyticTime = PROFILE_TRIGO_PROTEOLYTIC_TIME; + betaAmylaseTime = PROFILE_TRIGO_BETAAMYLASE_TIME; + alphaAmylaseTime = PROFILE_TRIGO_ALPHAAMYLASE_TIME; + mashoutTime = PROFILE_TRIGO_MASHOUT_TIME; + recirculationTime = PROFILE_TRIGO_RECIRCULATION_TIME; + spargeTime = PROFILE_TRIGO_SPARGE_TIME; + boilTime = PROFILE_TRIGO_BOIL_TIME; + coolingTime = PROFILE_TRIGO_COOLING_TIME; + startpointTemperature = PROFILE_TRIGO_STARTPOINT_TEMPERATURE; + betaGlucanaseTemperature = PROFILE_TRIGO_BETAGLUCANASE_TEMPERATURE; + debranchingTemperature = PROFILE_TRIGO_DEBRANCHING_TEMPERATURE; + proteolyticTemperature = PROFILE_TRIGO_PROTEOLYTIC_TEMPERATURE; + betaAmylaseTemperature = PROFILE_TRIGO_BETAAMYLASE_TEMPERATURE; + alphaAmylaseTemperature = PROFILE_TRIGO_ALPHAAMYLASE_TEMPERATURE; + mashoutTemperature = PROFILE_TRIGO_MASHOUT_TEMPERATURE; + recirculationTemperature = PROFILE_TRIGO_RECIRCULATION_TEMPERATURE; + spargeTemperature = PROFILE_TRIGO_SPARGE_TEMPERATURE; + boilTemperature = PROFILE_TRIGO_BOIL_TEMPERATURE; + coolingTemperature = PROFILE_TRIGO_COOLING_TEMPERATURE; + + backToStatus(); + break; + } + case eBeerProfileMenu_IPA: { + beerProfile = eBeerProfile_IPA; + startpointTime = PROFILE_IPA_STARTPOINT_TIME; + betaGlucanaseTime = PROFILE_IPA_BETAGLUCANASE_TIME; + debranchingTime = PROFILE_IPA_DEBRANCHING_TIME; + proteolyticTime = PROFILE_IPA_PROTEOLYTIC_TIME; + betaAmylaseTime = PROFILE_IPA_BETAAMYLASE_TIME; + alphaAmylaseTime = PROFILE_IPA_ALPHAAMYLASE_TIME; + mashoutTime = PROFILE_IPA_MASHOUT_TIME; + recirculationTime = PROFILE_IPA_RECIRCULATION_TIME; + spargeTime = PROFILE_IPA_SPARGE_TIME; + boilTime = PROFILE_IPA_BOIL_TIME; + coolingTime = PROFILE_IPA_COOLING_TIME; + startpointTemperature = PROFILE_IPA_STARTPOINT_TEMPERATURE; + betaGlucanaseTemperature = PROFILE_IPA_BETAGLUCANASE_TEMPERATURE; + debranchingTemperature = PROFILE_IPA_DEBRANCHING_TEMPERATURE; + proteolyticTemperature = PROFILE_IPA_PROTEOLYTIC_TEMPERATURE; + betaAmylaseTemperature = PROFILE_IPA_BETAAMYLASE_TEMPERATURE; + alphaAmylaseTemperature = PROFILE_IPA_ALPHAAMYLASE_TEMPERATURE; + mashoutTemperature = PROFILE_IPA_MASHOUT_TEMPERATURE; + recirculationTemperature = PROFILE_IPA_RECIRCULATION_TEMPERATURE; + spargeTemperature = PROFILE_IPA_SPARGE_TEMPERATURE; + boilTemperature = PROFILE_IPA_BOIL_TEMPERATURE; + coolingTemperature = PROFILE_IPA_COOLING_TEMPERATURE; + + backToStatus(); + break; + } + case eBeerProfileMenu_Belga: { + beerProfile = eBeerProfile_Belga; + startpointTime = PROFILE_BELGA_STARTPOINT_TIME; + betaGlucanaseTime = PROFILE_BELGA_BETAGLUCANASE_TIME; + debranchingTime = PROFILE_BELGA_DEBRANCHING_TIME; + proteolyticTime = PROFILE_BELGA_PROTEOLYTIC_TIME; + betaAmylaseTime = PROFILE_BELGA_BETAAMYLASE_TIME; + alphaAmylaseTime = PROFILE_BELGA_ALPHAAMYLASE_TIME; + mashoutTime = PROFILE_BELGA_MASHOUT_TIME; + recirculationTime = PROFILE_BELGA_RECIRCULATION_TIME; + spargeTime = PROFILE_BELGA_SPARGE_TIME; + boilTime = PROFILE_BELGA_BOIL_TIME; + coolingTime = PROFILE_BELGA_COOLING_TIME; + startpointTemperature = PROFILE_BELGA_STARTPOINT_TEMPERATURE; + betaGlucanaseTemperature = PROFILE_BELGA_BETAGLUCANASE_TEMPERATURE; + debranchingTemperature = PROFILE_BELGA_DEBRANCHING_TEMPERATURE; + proteolyticTemperature = PROFILE_BELGA_PROTEOLYTIC_TEMPERATURE; + betaAmylaseTemperature = PROFILE_BELGA_BETAAMYLASE_TEMPERATURE; + alphaAmylaseTemperature = PROFILE_BELGA_ALPHAAMYLASE_TEMPERATURE; + mashoutTemperature = PROFILE_BELGA_MASHOUT_TEMPERATURE; + recirculationTemperature = PROFILE_BELGA_RECIRCULATION_TEMPERATURE; + spargeTemperature = PROFILE_BELGA_SPARGE_TEMPERATURE; + boilTemperature = PROFILE_BELGA_BOIL_TEMPERATURE; + coolingTemperature = PROFILE_BELGA_COOLING_TEMPERATURE; + + backToStatus(); + break; + } + case eBeerProfileMenu_Red: { + beerProfile = eBeerProfile_Red; + startpointTime = PROFILE_RED_STARTPOINT_TIME; + betaGlucanaseTime = PROFILE_RED_BETAGLUCANASE_TIME; + debranchingTime = PROFILE_RED_DEBRANCHING_TIME; + proteolyticTime = PROFILE_RED_PROTEOLYTIC_TIME; + betaAmylaseTime = PROFILE_RED_BETAAMYLASE_TIME; + alphaAmylaseTime = PROFILE_RED_ALPHAAMYLASE_TIME; + mashoutTime = PROFILE_RED_MASHOUT_TIME; + recirculationTime = PROFILE_RED_RECIRCULATION_TIME; + spargeTime = PROFILE_RED_SPARGE_TIME; + boilTime = PROFILE_RED_BOIL_TIME; + coolingTime = PROFILE_RED_COOLING_TIME; + startpointTemperature = PROFILE_RED_STARTPOINT_TEMPERATURE; + betaGlucanaseTemperature = PROFILE_RED_BETAGLUCANASE_TEMPERATURE; + debranchingTemperature = PROFILE_RED_DEBRANCHING_TEMPERATURE; + proteolyticTemperature = PROFILE_RED_PROTEOLYTIC_TEMPERATURE; + betaAmylaseTemperature = PROFILE_RED_BETAAMYLASE_TEMPERATURE; + alphaAmylaseTemperature = PROFILE_RED_ALPHAAMYLASE_TEMPERATURE; + mashoutTemperature = PROFILE_RED_MASHOUT_TEMPERATURE; + recirculationTemperature = PROFILE_RED_RECIRCULATION_TEMPERATURE; + spargeTemperature = PROFILE_RED_SPARGE_TEMPERATURE; + boilTemperature = PROFILE_RED_BOIL_TEMPERATURE; + coolingTemperature = PROFILE_RED_COOLING_TEMPERATURE; + + backToStatus(); + break; + } + case eBeerProfileMenu_APA: { + beerProfile = eBeerProfile_APA; + startpointTime = PROFILE_APA_STARTPOINT_TIME; + betaGlucanaseTime = PROFILE_APA_BETAGLUCANASE_TIME; + debranchingTime = PROFILE_APA_DEBRANCHING_TIME; + proteolyticTime = PROFILE_APA_PROTEOLYTIC_TIME; + betaAmylaseTime = PROFILE_APA_BETAAMYLASE_TIME; + alphaAmylaseTime = PROFILE_APA_ALPHAAMYLASE_TIME; + mashoutTime = PROFILE_APA_MASHOUT_TIME; + recirculationTime = PROFILE_APA_RECIRCULATION_TIME; + spargeTime = PROFILE_APA_SPARGE_TIME; + boilTime = PROFILE_APA_BOIL_TIME; + coolingTime = PROFILE_APA_COOLING_TIME; + startpointTemperature = PROFILE_APA_STARTPOINT_TEMPERATURE; + betaGlucanaseTemperature = PROFILE_APA_BETAGLUCANASE_TEMPERATURE; + debranchingTemperature = PROFILE_APA_DEBRANCHING_TEMPERATURE; + proteolyticTemperature = PROFILE_APA_PROTEOLYTIC_TEMPERATURE; + betaAmylaseTemperature = PROFILE_APA_BETAAMYLASE_TEMPERATURE; + alphaAmylaseTemperature = PROFILE_APA_ALPHAAMYLASE_TEMPERATURE; + mashoutTemperature = PROFILE_APA_MASHOUT_TEMPERATURE; + recirculationTemperature = PROFILE_APA_RECIRCULATION_TEMPERATURE; + spargeTemperature = PROFILE_APA_SPARGE_TEMPERATURE; + boilTemperature = PROFILE_APA_BOIL_TEMPERATURE; + coolingTemperature = PROFILE_APA_COOLING_TEMPERATURE; + + backToStatus(); + break; + } + case eBeerProfileMenu_Custom: { + beerProfile = eBeerProfile_Custom; + startpointTime = PROFILE_CUSTOM_STARTPOINT_TIME; + betaGlucanaseTime = PROFILE_CUSTOM_BETAGLUCANASE_TIME; + debranchingTime = PROFILE_CUSTOM_DEBRANCHING_TIME; + proteolyticTime = PROFILE_CUSTOM_PROTEOLYTIC_TIME; + betaAmylaseTime = PROFILE_CUSTOM_BETAAMYLASE_TIME; + alphaAmylaseTime = PROFILE_CUSTOM_ALPHAAMYLASE_TIME; + mashoutTime = PROFILE_CUSTOM_MASHOUT_TIME; + recirculationTime = PROFILE_CUSTOM_RECIRCULATION_TIME; + spargeTime = PROFILE_CUSTOM_SPARGE_TIME; + boilTime = PROFILE_CUSTOM_BOIL_TIME; + coolingTime = PROFILE_CUSTOM_COOLING_TIME; + startpointTemperature = PROFILE_CUSTOM_STARTPOINT_TEMPERATURE; + betaGlucanaseTemperature = PROFILE_CUSTOM_BETAGLUCANASE_TEMPERATURE; + debranchingTemperature = PROFILE_CUSTOM_DEBRANCHING_TEMPERATURE; + proteolyticTemperature = PROFILE_CUSTOM_PROTEOLYTIC_TEMPERATURE; + betaAmylaseTemperature = PROFILE_CUSTOM_BETAAMYLASE_TEMPERATURE; + alphaAmylaseTemperature = PROFILE_CUSTOM_ALPHAAMYLASE_TEMPERATURE; + mashoutTemperature = PROFILE_CUSTOM_MASHOUT_TEMPERATURE; + recirculationTemperature = PROFILE_CUSTOM_RECIRCULATION_TEMPERATURE; + spargeTemperature = PROFILE_CUSTOM_SPARGE_TEMPERATURE; + boilTemperature = PROFILE_CUSTOM_BOIL_TEMPERATURE; + coolingTemperature = PROFILE_CUSTOM_COOLING_TEMPERATURE; + + backToStatus(); + break; + } + case eBeerProfileMenu_Back: { + resetMenu( true ); + break; + } + default: {} } - return false; -} - -//HEATING_ELEMENT_MAX_WATTAGE / HEATING_ELEMENT_AC_FREQUENCY_HZ -double ulWattToWindowTime( double ulAppliedWatts ) { - double ulPulsesRequired = ulAppliedWatts / dWattPerPulse; - return (double)iWindowSize / 1000.0 * ulPulsesRequired * 1000.0 / HEATING_ELEMENT_AC_FREQUENCY_HZ; + mdBeerProfileMenu._selection = eBeerProfileMenu_NULL; } -bool xRegulateTemperature( boolean bMaximumOfUpDown ) { - double difference = 0; - bool overTemperature = false; - double wattage = 0.0; - - float tup = upPT100.getCurrentTemperature(); - float tdown = downPT100.getCurrentTemperature(); - float tbase = basePT100.getCurrentTemperature(); - - if ( bMaximumOfUpDown ) { - if (tup > tdown) { - difference = cookTemperature - tup; +void runStageSelection() { + switch (mdStageMenu._selection) { + case eStageMenu_Startpoint: { + runStageSelection_Generic( &startpointTime, &startpointTemperature ); + break; } - else { - difference = cookTemperature - tdown; + case eStageMenu_BetaGlucanase: { + runStageSelection_Generic( &betaGlucanaseTime, &betaGlucanaseTemperature ); + break; } - - if (tbase > cookTemperature && (tbase >= (PUMP_TEMPERATURE_MAX_OPERATION - 2.0) || difference >= 5.0)) { - difference = cookTemperature - tbase; + case eStageMenu_Debranching: { + runStageSelection_Generic( &debranchingTime, &debranchingTemperature ); + break; } - - if ( (tbase < cookTemperature) && (difference < (cookTemperature - tbase)) ) { - difference = cookTemperature - tbase; + case eStageMenu_Proteolytic: { + runStageSelection_Generic( &proteolyticTime, &proteolyticTemperature ); + break; } - } else { - difference = cookTemperature - tbase; - } - - // Deviation between the cook temperature set and the cook temperature measured - if ( difference < 0.0 ) { - difference = difference * (-1.0); - overTemperature = true; + case eStageMenu_BetaAmylase: { + runStageSelection_Generic( &betaAmylaseTime, &betaAmylaseTemperature ); + break; + } + case eStageMenu_AlphaAmylase: { + runStageSelection_Generic( &alphaAmylaseTime, &alphaAmylaseTemperature ); + break; + } + case eStageMenu_Mashout: { + runStageSelection_Generic( &mashoutTime, &mashoutTemperature ); + break; + } + case eStageMenu_Recirculation: { + runStageSelection_Generic( &recirculationTime, &recirculationTemperature ); + break; + } + case eStageMenu_Sparge: { + runStageSelection_Generic( &spargeTime, &spargeTemperature ); + break; + } + case eStageMenu_Boil: { + runStageSelection_Generic( &boilTime, &boilTemperature ); + break; + } + case eStageMenu_Cooling: { + runStageSelection_Generic( &coolingTime, &coolingTemperature ); + break; + } + case eStageMenu_Back: { + resetMenu( true ); + break; + } + default: {} } + mdStageMenu._selection = eStageMenu_NULL; +} - // Calculate applied wattage, based on the distance from the target temperature - if ( overTemperature ) { - // turn it off - wattage = 0.0; - } else { - //if(difference <= 0.1) { - // turn it off - // wattage = 0.0; - //} else { - if (difference <= 0.5) { - // pulse lightly at 500 watt - if (cookTemperature > 99.0) { - wattage = 2000.0; - } - else { - if (cookTemperature > 70.0) { - wattage = 1000.0; - } - else { - wattage = 500.0; - } - } - } else { - if (difference <= 1.0) { - // pulse moderately at 1000 watt - if (cookTemperature > 99.0) { - wattage = 2000.0; - } - else { - wattage = 1000.0; - } - - } else { - if (difference <= 3.0) { - // pulse hardly at 2000 watt - wattage = 2000.0; +void runSettingsSelection() { + switch (mdSettingsMenu._selection) { + case eSettingsMenu_Pump: { + // Stuff + if ( xSetGenericValue( iPumpSpeed ? 0 : 1, 0, 1, "pump", "bool" ) ) { + iPumpSpeed = PUMP_SPEED_MAX_MOSFET; } else { - //pulse constantly at HEATING_ELEMENT_MAX_WATTAGE watt - wattage = HEATING_ELEMENT_MAX_WATTAGE; + iPumpSpeed = PUMP_SPEED_STOP_MOSFET; } + analogWrite(PUMP_PIN, iPumpSpeed); + backToStatus(); + break; + } + case eSettingsMenu_PT100_Element: { + backToStatus(); + break; + } + case eSettingsMenu_PT100_Up: { + backToStatus(); + break; + } + case eSettingsMenu_PT100_Down: { + backToStatus(); + break; } + case eSettingsMenu_Back: { + resetMenu( true ); + break; } - //} - } - - // Update the recorded time for the begining of the window, if the previous window has passed - while ((millis() - windowStartTime) > iWindowSize) { // Check if it's time to vary the pulse width modulation and if so do it by shifting the "Relay in ON" Window - windowStartTime += iWindowSize; - } - - // Apply wattage to the element at the right time - if ( ulWattToWindowTime( wattage ) > (millis() - windowStartTime) ) { - digitalWrite(HEATING_ELEMENT_OUTPUT_PIN, HIGH); - bStatusElement = true; - } else { - digitalWrite(HEATING_ELEMENT_OUTPUT_PIN, LOW); - bStatusElement = false; + default: {} } - -#ifdef DEBUG_OFF - //debugPrintFunction("xRegulateTemperature"); - debugPrintVar("difference", difference); - //debugPrintVar("overTemperature", overTemperature); - debugPrintVar("wattage", wattage); - //debugPrintVar("ulWattToWindowTime( wattage )", ulWattToWindowTime( wattage ) ); - //debugPrintVar("millis()", millis()); - //debugPrintVar("windowStartTime", windowStartTime); - //debugPrintVar("test", ulWattToWindowTime( wattage ) > (millis() - windowStartTime) ); -#endif + mdSettingsMenu._selection = eSettingsMenu_NULL; } -void xPurgePump() { - for (int i = 0; i < 2; i++) { - analogWrite(PUMP_PIN, PUMP_SPEED_MAX_MOSFET); // analogWrite values from 0 to 255 - delay(1000); - analogWrite(PUMP_PIN, PUMP_SPEED_STOP_MOSFET); // analogWrite values from 0 to 255 - delay(1500); +void runMaltSelection() { + switch (mdMaltMenu._selection) { + case eMaltMenu_CastleMalting_Chteau_Pilsen_2RS: { + backToStatus(); + break; + } + case eMaltMenu_CastleMalting_Wheat_Blanc: { + backToStatus(); + break; + } + case eMaltMenu_Back: { + resetMenu( true ); + break; + } + default: {} } + mdMaltMenu._selection = eMaltMenu_NULL; } -bool xRegulatePumpSpeed() { - // analogWrite(PUMP_PIN, iPumpSpeed); // analogWrite values from 0 to 255 +// ************************ MENU HELPERS ****************************** +void runMenuProcessor( MenuData *data ) { + data->_position = rotaryEncoderVirtualPosition; // Read position - if (basePT100.getCurrentTemperature() > PUMP_TEMPERATURE_MAX_OPERATION) { - analogWrite(PUMP_PIN, PUMP_SPEED_STOP_MOSFET); // analogWrite values from 0 to 255 + data->_repaint = repaint; // Request repaint + repaint = displayGenericMenu( &lcd, data ); // Display menu - basePT100.setPumpStatus( false ); - upPT100.setPumpStatus( false ); - downPT100.setPumpStatus( false ); + if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) { // Read selection + data->_selection = data->_position; } - else { - analogWrite(PUMP_PIN, iPumpSpeed); // analogWrite values from 0 to 255 + + (data->_selectionFunction)(); // Run selection function +} - basePT100.setPumpStatus( true ); - upPT100.setPumpStatus( true ); - downPT100.setPumpStatus( true ); - } +void runStageSelection_Generic( unsigned long * selectedStageTime, int *selectedStageTemperature) { + (*selectedStageTime) = getTimer( (*selectedStageTime) ); + (*selectedStageTemperature) = xSetGenericValue( (*selectedStageTemperature), TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, MENU_GLOBAL_STR_TEMPERATURE, MENU_GLOBAL_STR_CELSIUS ); + backToStatus(); } -void xWarnClockEnded() { - sing(MELODY_SUPER_MARIO_START, PIEZO_PIN); +void xStartStageHeadless( eCookingStages nextStage, bool bPurgePump ) { + xStartStage( NULL, NULL, nextStage, bPurgePump, false, false, false ); } -void xWarnCookEnded() { - sing(MELODY_UNDERWORLD_SHORT, PIEZO_PIN); +void xStartStageInteractive( unsigned long *stageTime, int *stageTemperature, eCookingStages nextStage ) { + xStartStage( stageTime, stageTemperature, nextStage, true, true, true, true ); } -void xPrepareForStage( int stageTime, int stageTemperature, int stagePumpSpeed, eCookingStages stage ) { -#ifdef DEBUG_OFF - debugPrintFunction("xPrepareForStage"); - debugPrintVar("cookingStage", stage); -#endif +void xStartStage( unsigned long *stageTime, int *stageTemperature, eCookingStages nextStage, bool bPurgePump, bool bSetFinalYield, bool bSetTime, bool bSetTemperature ) { + xSafeHardwarePowerOff(); // Stop anything that might be still going on - // Reset the clock - unsigned long now = millis(); - clockStartTime = now; - clockLastUpdate = now; - clockIgnore = 0; - - iPumpSpeed = stagePumpSpeed; // Set the pump speed - cookingStage = stage; // Set Stage - cookTime = stageTime; // Set the clock - cookTemperature = stageTemperature; // Set the target temperature -} - -void xSetupStage(eCookingStages nextStage) { -#ifdef DEBUG_OFF - debugPrintFunction("xSetupStage"); - debugPrintVar("cookingStage", nextStage); -#endif - - // Operate the machine according to the current mode - switch (nextStage) { - case eCookingStage_Startpoint: { - switch (beerProfile) { - case eBeerProfile_Trigo: { - float wheatAmount = 0.05 * ((float) finalYield); - float pilsnerAmount = 0.2 * ((float) finalYield); - String say = "Cruch "; - say += String(wheatAmount); - say += String("Kg of Wheat and "); - say += String(pilsnerAmount); - say += String("Kg of Pilsner Malt into a pot."); - - xWaitForAction("Malt", say); - repaint = true; - break; - } - case eBeerProfile_IPA: { - float caramelAmount = 0.013157895 * ((float) finalYield); - float wheatAmount = 0.060526316 * ((float) finalYield); - float pilsnerAmount = 0.115789474 * ((float) finalYield); - float munichAmount = 0.028947368 * ((float) finalYield); - String say = "Cruch "; - say += String(caramelAmount); - say += String("Kg of Caramel 120, "); - say += String(wheatAmount); - say += String("Kg of Wheat, "); - say += String(pilsnerAmount); - say += String("Kg of Pilsner, "); - say += String(munichAmount); - say += String("Kg of Munich into a pot."); - - xWaitForAction("Malt", say); - repaint = true; - break; - } - default: { - - } - } - - // Make sure there is water - xWaitForAction("Water", "Make sure there is water in the machine before start cooking."); - - repaint = true; - xPrepareForStage( startpointTime, startpointTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Startpoint ); - break; - } - case eCookingStage_BetaGlucanase: { - switch (beerProfile) { - case eBeerProfile_Trigo: { - float wheatAmount = 0.05 * ((float) finalYield); - float pilsnerAmount = 0.2 * ((float) finalYield); - String say = "Put "; - say += String(wheatAmount); - say += String("Kg of Wheat and "); - say += String(pilsnerAmount); - say += String("Kg of Pilsner Malt in."); - - xWaitForAction("Malt", say); - repaint = true; - break; - } - case eBeerProfile_IPA: { - float caramelAmount = 0.013157895 * ((float) finalYield); - float wheatAmount = 0.060526316 * ((float) finalYield); - float pilsnerAmount = 0.115789474 * ((float) finalYield); - float munichAmount = 0.028947368 * ((float) finalYield); - String say = "Cruch "; - say += String(caramelAmount); - say += String("Kg of Caramel 120, "); - say += String(wheatAmount); - say += String("Kg of Wheat, "); - say += String(pilsnerAmount); - say += String("Kg of Pilsner, "); - say += String(munichAmount); - say += String("Kg of Munich into a pot."); - - xWaitForAction("Malt", say); - repaint = true; - break; - } - default: {} - } - xPrepareForStage( betaGlucanaseTime, betaGlucanaseTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_BetaGlucanase ); - break; - } - case eCookingStage_Debranching: { - xPrepareForStage( debranchingTime, debranchingTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Debranching ); - break; - } - case eCookingStage_Proteolytic: { - xPrepareForStage( proteolyticTime, proteolyticTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Proteolytic ); - break; - } - case eCookingStage_BetaAmylase: { - xPrepareForStage( betaAmylaseTime, betaAmylaseTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_BetaAmylase ); - break; - } - case eCookingStage_AlphaAmylase: { - xPrepareForStage( alphaAmylaseTime, alphaAmylaseTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_AlphaAmylase ); - break; - } - case eCookingStage_Mashout: { - xPrepareForStage( mashoutTime, mashoutTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Mashout ); - break; - } - case eCookingStage_Recirculation: { - xWaitForAction("Sparge Water", "Start heating your sparge water."); - repaint = true; - xPrepareForStage( recirculationTime, recirculationTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Recirculation ); - break; - } - case eCookingStage_Sparge: { - xWaitForAction("Sparge Water", "Start pouring the sparge water."); - repaint = true; - xPrepareForStage( spargeTime, spargeTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Sparge ); - break; - } - case eCookingStage_Boil: { - switch (beerProfile) { - case eBeerProfile_Trigo: { - String say = "Get "; - - float hopAmount = 0.8 * ((float) finalYield); - say += String(hopAmount); - - say += String("g of Magnum 9.4\% and Styrian Golding 5\% ready."); - - xWaitForAction("Hops", say); - - break; - } - case eBeerProfile_IPA: { - String say = "Get "; - - float hopAmount = 0.8 * ((float) finalYield); - say += String(hopAmount); - - say += String("g of Chinook, Cascade and Styrian Golding ready."); - - xWaitForAction("Hops", say); - - break; - } - default: { - xWaitForAction("Hops", "Add the hops in the right order, at the right time."); - - } - } - - repaint = true; - - // A basic operation for a basic stage - xPrepareForStage( boilTime, boilTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Boil ); - - break; - } - case eCookingStage_Cooling: { - // Make sure there is water - xWaitForAction("Coil", "Add the coil and connect it to the main water supply."); - - repaint = true; - - // A basic operation for a basic stage - xPrepareForStage( coolingTime, coolingTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Cooling ); - - break; - } - case eCookingStage_Clean: { - // Make sure there is water - xWaitForAction("Water", "Add 13 liters."); - - // Make sure there is water - xWaitForAction("Star San HB", "Add 0.89oz/26ml."); - - repaint = true; - - // A basic operation for a basic stage - xPrepareForStage( cleaningTime, cleaningTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Clean ); - - break; - } - case eCookingStage_Purge: { - // A basic operation for a basic stage - xPrepareForStage( 0, 0, PUMP_SPEED_MAX_MOSFET, eCookingStage_Purge ); - - xRegulatePumpSpeed(); - - break; - } - case eCookingStage_Done: { - // A basic operation for a basic stage - xPrepareForStage( 0, 0, PUMP_SPEED_STOP_MOSFET, eCookingStage_Done ); - - break; - } - } -} - -void xTransitionIntoStage(eCookingStages nextStage) { - // Turn off all hardware that can damage itself if the machine is not cooking - xSafeHardwarePowerOff(); - - // Warn the user a stage has ended - xWarnClockEnded(); - - // Reset global stage variables - xSetupStage( nextStage ); -} - -void xBasicStageOperation( int iStageTime, int iStageTemperature, int iStageTemperatureRange, eCookingStages nextStage, boolean bMaximumOfUpDown ) { - - // Account for time spent at the target temperature | Input 1: range in ºC within which the target temperature is considered to be reached -#ifdef DEBUG_OFF - xCountTheTime( iStageTemperatureRange, false ); -#else - xCountTheTime( iStageTemperatureRange, bMaximumOfUpDown ); -#endif - - if ( isTimeLeft() ) { - // Do temperature control - xRegulateTemperature( bMaximumOfUpDown ); - - // Do flow control - xRegulatePumpSpeed(); - - } else { -#ifdef DEBUG_OFF - debugPrintFunction("xBasicStageOperation"); - debugPrintVar("clockCounter", clockCounter); -#endif - - // Continue to the next stage, there is nothing to do, in this stage - xTransitionIntoStage( nextStage ); - return; - } - - return; -} - -void xManageMachineSystems() { - -#ifdef DEBUG - Serial.print(millis()); - Serial.print(","); - if (cooking) { - Serial.print("1"); - } - else { - Serial.print("0"); + if (bSetFinalYield) { + finalYield = xSetFinalYield( finalYield ); } - Serial.print(","); - Serial.print(cookTemperature); - Serial.print(","); - if (bStatusElement) { - Serial.print("1"); + if (bSetTime) { + (*stageTime) = getTimer( clockCounter / 1000, (*stageTime) ); } - else { - Serial.print("0"); + if (bSetTemperature) { + (*stageTemperature) = xSetTemperature( (*stageTemperature) ); } - Serial.print(","); -#endif - - // Measure temperature, for effect - basePT100.measure(false); - upPT100.measure(false); - downPT100.measure(true); - - // If cooking is done, return (this is a nice place to double check safety and ensure the cooking parts aren't on. - if (!cooking) { - xSafeHardwarePowerOff(); - - return; + if (bPurgePump) { + xPurgePump(); } - // Operate the machine according to the current mode - switch (cookingStage) { - case eCookingStage_Startpoint: { - // A basic operation for a basic stage - xBasicStageOperation( startpointTime, startpointTemperature, 0, eCookingStage_BetaGlucanase, false); - - break; - } - case eCookingStage_BetaGlucanase: { - // A basic operation for a basic stage - xBasicStageOperation( betaGlucanaseTime, betaGlucanaseTemperature, 3, eCookingStage_Debranching, true ); - - break; - } - case eCookingStage_Debranching: { - // A basic operation for a basic stage - xBasicStageOperation( debranchingTime, debranchingTemperature, 3, eCookingStage_Proteolytic, true ); - - break; - } - case eCookingStage_Proteolytic: { - // A basic operation for a basic stage - xBasicStageOperation( proteolyticTime, proteolyticTemperature, 3, eCookingStage_BetaAmylase, true ); - - break; - } - case eCookingStage_BetaAmylase: { - // A basic operation for a basic stage - xBasicStageOperation( betaAmylaseTime, betaAmylaseTemperature, 4, eCookingStage_AlphaAmylase, true ); - - break; - } - case eCookingStage_AlphaAmylase: { - // A basic operation for a basic stage - xBasicStageOperation( alphaAmylaseTime, alphaAmylaseTemperature, 2, eCookingStage_Mashout, true ); - - break; - } - case eCookingStage_Mashout: { - // A basic operation for a basic stage - xBasicStageOperation( mashoutTime, mashoutTemperature, 1, eCookingStage_Recirculation, true ); - - break; - } - case eCookingStage_Recirculation: { - // A basic operation for a basic stage - xBasicStageOperation( recirculationTime, recirculationTemperature, 1, eCookingStage_Sparge, true ); - - break; - } - case eCookingStage_Sparge: { - // A basic operation for a basic stage - xBasicStageOperation( spargeTime, spargeTemperature, 3, eCookingStage_Boil, false ); - - break; - } - case eCookingStage_Boil: { - // A basic operation for a basic stage - xBasicStageOperation( boilTime, boilTemperature, 2, eCookingStage_Cooling, false ); - - break; - } - case eCookingStage_Cooling: { - // A basic operation for a basic stage - xBasicStageOperation( coolingTime, coolingTemperature, 0, eCookingStage_Done, false ); - - break; - } - case eCookingStage_Clean: { - // A basic operation for a basic stage - xBasicStageOperation( cleaningTime, cleaningTemperature, 0, eCookingStage_Done, false ); - - break; - } - case eCookingStage_Purge: { - // A basic operation for a basic stage - //xBasicStageOperation( coolingTime, coolingTemperature, 1, eCookingStage_Done ); - iPumpSpeed = PUMP_SPEED_MAX_MOSFET; - - xRegulatePumpSpeed(); - - break; - } - case eCookingStage_Done: { - // Update cooking state - stopBrewing(); - - // Ask for screen refresh - repaint = true; - - // Warn the user that the cooking is done - xWarnCookEnded(); - - break; - } - } + startBrewing(); + xSetupStage( nextStage ); + backToStatus(); } +// ##################################################### Menus ################################################################### // #################################################### Helpers ################################################################## @@ -1708,7 +1495,6 @@ void resetMenu( boolean requestRepaintPaint ) { } // reset operation state | INPUT : eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep - //xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenuPosition, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 ); xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMainMenu._position, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 ); } diff --git a/config.h b/config.h index 44e29570439a7d01ca48efcb3c43429fa16c2342..862701fd461a3843a9cef056a2ee900795a923af 100644 --- a/config.h +++ b/config.h @@ -95,36 +95,45 @@ #define MENU_MAIN_INIT_POSITION eMainMenu_GO #define MENU_MAIN_INIT_SELECTION eMainMenu_NULL #define MENU_MAIN_INIT_REPAINT false +#define MENU_MAIN_FUNCTION &runMainMenuSelection #define MENU_PROFILE_TITLE "Profile Menu" #define MENU_PROFILE_DIALOG {"", "-> Basic ", "-> Trigo ", "-> IPA ", "-> Belga ", "-> Red ", "-> APA ", "-> Custom ", "-> Back " } #define MENU_PROFILE_INIT_POSITION eBeerProfileMenu_Basic #define MENU_PROFILE_INIT_SELECTION eBeerProfileMenu_NULL #define MENU_PROFILE_INIT_REPAINT false +#define MENU_PROFILE_FUNCTION &runBeerProfileSelection #define MENU_STAGE_TITLE "Stage Menu" #define MENU_STAGE_DIALOG {"", "-> Startpoint ", "-> BetaGlucanase", "-> Debranching ", "-> Proteolytic ", "-> Beta Amylase ", "-> Alpha Amylase", "-> Mashout ", "-> Recirculation", "-> Sparge ", "-> Boil ", "-> Cooling ", "-> Back " } #define MENU_STAGE_INIT_POSITION eStageMenu_Startpoint #define MENU_STAGE_INIT_SELECTION eStageMenu_NULL #define MENU_STAGE_INIT_REPAINT false +#define MENU_STAGE_FUNCTION &runStageSelection #define MENU_MALT_TITLE "Malt Menu" #define MENU_MALT_DIALOG {"", "-> CM Ch. Pilsen", "-> CM Wheat Blan", "-> Back " } #define MENU_MALT_INIT_POSITION eMaltMenu_CastleMalting_Chteau_Pilsen_2RS #define MENU_MALT_INIT_SELECTION eMaltMenu_NULL #define MENU_MALT_INIT_REPAINT false +#define MENU_MALT_FUNCTION &runMaltSelection #define MENU_SETTINGS_TITLE "Settings Menu" #define MENU_SETTINGS_DIALOG {"", "-> PT100 Element", "-> PT100 Up ", "-> PT100 Down ", "-> Back " } #define MENU_SETTINGS_INIT_POSITION eSettingsMenu_PT100_Element #define MENU_SETTINGS_INIT_SELECTION eSettingsMenu_NULL #define MENU_SETTINGS_INIT_REPAINT false +#define MENU_SETTINGS_FUNCTION &runSettingsSelection + +#define MENU_GLOBAL_STR_TEMPERATURE "temperature" +#define MENU_GLOBAL_STR_CELSIUS "*C" #define MENU_START_TITLE MENU_STAGE_TITLE #define MENU_START_DIALOG MENU_STAGE_DIALOG #define MENU_START_INIT_POSITION MENU_STAGE_INIT_POSITION #define MENU_START_INIT_SELECTION MENU_STAGE_INIT_SELECTION #define MENU_START_INIT_REPAINT MENU_STAGE_INIT_REPAINT +#define MENU_START_FUNCTION &runStartFromStageSelection // ++++++++++++++++++++++++ Serial Monotor ++++++++++++++++++++++++ #define SETTING_SERIAL_MONITOR_BAUD_RATE 9600