brew.ino 73.3 KB
Newer Older
João Lino's avatar
Rel.3  
João Lino committed
1 2 3 4 5
/*
  brew.ino - Main execution file.
  Created by João Lino, August 28, 2014.
  Released into the public domain.
*/
6

João Lino's avatar
João Lino committed
7 8
//#define DEBUG
#define INFO
9
#define HEATING_ELEMENT_ALWAYS_OFF
João Lino's avatar
João Lino committed
10
#define PUMP_ALWAYS_OFF
11

12
// ######################### LIBRARIES #########################
João Lino's avatar
João Lino committed
13
#include "brew.h"
14

15
// ######################### VARIABLES #########################
16
// ++++++++++++++++++++++++ State Machine ++++++++++++++++++++++++
17
eRotaryEncoderMode      rotaryEncoderMode;
João Lino's avatar
Rel.3  
João Lino committed
18 19 20 21 22 23

eCookingStages          cookingStage;
eBeerProfile            beerProfile;

eMenuType               eMenuType;

João Lino's avatar
João Lino committed
24 25 26 27 28 29
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 };
João Lino's avatar
Rel.3  
João Lino committed
30

31
// ++++++++++++++++++++++++ Global Variables ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
32 33
boolean                 cooking;

João Lino's avatar
Rel.3  
João Lino committed
34 35 36 37
unsigned long           clockStartTime;
unsigned long           clockLastUpdate;
long                    clockCounter;
unsigned long           clockIgnore;
João Lino's avatar
João Lino committed
38 39 40
boolean                 clockStart;
boolean                 clockEnd;

João Lino's avatar
Rel.3  
João Lino committed
41
unsigned long           cookTime;
João Lino's avatar
João Lino committed
42
int                     cookTemperature;
João Lino's avatar
Rel.3  
João Lino committed
43
int                     finalYield;
44

João Lino's avatar
Rel.3  
João Lino committed
45 46 47 48 49 50 51 52 53 54 55 56
unsigned long           startpointTime;
unsigned long           betaGlucanaseTime;
unsigned long           debranchingTime;
unsigned long           proteolyticTime;
unsigned long           betaAmylaseTime;
unsigned long           alphaAmylaseTime;
unsigned long           mashoutTime;
unsigned long           recirculationTime;
unsigned long           spargeTime;
unsigned long           boilTime;
unsigned long           coolingTime;
unsigned long           cleaningTime;
57

João Lino's avatar
João Lino committed
58 59 60 61 62 63 64 65 66 67 68
int                     startpointTemperature;
int                     betaGlucanaseTemperature;
int                     debranchingTemperature;
int                     proteolyticTemperature;
int                     betaAmylaseTemperature;
int                     alphaAmylaseTemperature;
int                     mashoutTemperature;
int                     recirculationTemperature;
int                     spargeTemperature;
int                     boilTemperature;
int                     coolingTemperature;
João Lino's avatar
Rel.3  
João Lino committed
69
int                     cleaningTemperature;
João Lino's avatar
João Lino committed
70 71 72

boolean                 refresh;
boolean                 repaint;
João Lino's avatar
João Lino committed
73
boolean                 cancel;
74

75
//boolean                 bStatusElement;
João Lino's avatar
Rel.3  
João Lino committed
76

João Lino's avatar
João Lino committed
77 78 79
unsigned long           loggingTimeInterval;


80
// ++++++++++++++++++++++++ Interrupts ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
81
static unsigned long    lastInterruptTime;
82

83
// ++++++++++++++++++++++++ Rotary Encoder ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
84 85 86 87 88
volatile int            rotaryEncoderVirtualPosition = 0;
volatile int            rotaryEncoderMaxPosition = 1;
volatile int            rotaryEncoderMinPosition = 0;
volatile int            rotaryEncoderSingleStep = 1;
volatile int            rotaryEncoderMultiStep = 1;
89

João Lino's avatar
João Lino committed
90 91
volatile boolean        onISR = false;

João Lino's avatar
João Lino committed
92 93
unsigned long           rotarySwDetectTime;

94
// ++++++++++++++++++++++++ Heating Element Relay ++++++++++++++++++++++++
95
HeatingElement          heatingElement(HEATING_ELEMENT_OUTPUT_PIN, LOW, HIGH);
96
/*
João Lino's avatar
João Lino committed
97 98 99
int                     iWindowSize;             // Time frame to operate in
unsigned long           windowStartTime;
double                  dWattPerPulse;
João Lino's avatar
João Lino committed
100
double                  dWattage;
101
*/
102

103
// ++++++++++++++++++++++++ Pump ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
104 105
Pump                    pump(PUMP_PIN, PUMP_SPEED_STOP_MOSFET, PUMP_SPEED_MAX_MOSFET, PUMP_TEMPERATURE_MAX_OPERATION, PUMP_PRIMING_TIME_IN_SECONDS);
//int                     iPumpSpeed;             // Time frame to operate in
106

107
// ######################### INITIALIZE #########################
108
// ++++++++++++++++++++++++ Library - LiquidCrystal_I2C ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
109
LiquidCrystal_I2C       lcd(LCD_I2C_ADDR, LCD_EN_PIN, LCD_RW_PIN, LCD_RS_PIN, LCD_D4_PIN, LCD_D5_PIN, LCD_D6_PIN, LCD_D7_PIN);
110

João Lino's avatar
João Lino committed
111
// +++++++++++++++++++++++ Temperature +++++++++++++++++++++++
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
Temperature                   basePT100("base",
                                        PT100_BASE_OUTPUT_PIN,
                                        PT100_BASE_INPUT_PIN,
                                        PT100_BASE_TIME_BETWEEN_READINGS,
                                        2.0298, 2.0259, 665.24, 662.17);
Temperature                   upPT100("up",
                                      PT100_UP_OUTPUT_PIN,
                                      PT100_UP_INPUT_PIN,
                                      PT100_UP_TIME_BETWEEN_READINGS,
                                      2.0274, 2.0245, 659.43, 656.72);
Temperature                   downPT100("down",
                                        PT100_DOWN_OUTPUT_PIN,
                                        PT100_DOWN_INPUT_PIN,
                                        PT100_DOWN_TIME_BETWEEN_READINGS,
                                        2.0309, 2.0288, 658.15, 655.35);
127 128

// ######################### INTERRUPTS #########################
João Lino's avatar
João Lino committed
129
void isr ()  {    // Interrupt service routine is executed when a HIGH to LOW transition is detected on CLK
130
  unsigned long interruptTime = millis();
João Lino's avatar
João Lino committed
131
  unsigned long diff = interruptTime - lastInterruptTime;
132

133
  // If interrupts come faster than [ROTARY_ENCODER_DEBOUNCE_TIME]ms, assume it's a bounce and ignore
João Lino's avatar
João Lino committed
134
  if (diff > ROTARY_ENCODER_DEBOUNCE_TIME) {
João Lino's avatar
João Lino committed
135
    lastInterruptTime = interruptTime;
136 137

    switch (rotaryEncoderMode) {
138 139
      // Input of rotary encoder controling menus
      case eRotaryEncoderMode_Menu: {
140
          if (!digitalRead(ROTARY_ENCODER_DT_PIN)) {
141
            rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + rotaryEncoderSingleStep);
142 143
          }
          else {
144
            rotaryEncoderVirtualPosition = rotaryEncoderVirtualPosition - rotaryEncoderSingleStep;
145 146
          }
          if (rotaryEncoderVirtualPosition > rotaryEncoderMaxPosition) {
João Lino's avatar
João Lino committed
147
            rotaryEncoderVirtualPosition = rotaryEncoderMaxPosition;
148 149
          }
          if (rotaryEncoderVirtualPosition < rotaryEncoderMinPosition) {
João Lino's avatar
João Lino committed
150
            rotaryEncoderVirtualPosition = rotaryEncoderMinPosition;
151 152 153
          }

          break;
154
        }
155

156 157
      // Input of rotary encoder controling time variables
      case eRotaryEncoderMode_Time: {
158 159 160 161 162 163 164
          if (!digitalRead(ROTARY_ENCODER_DT_PIN)) {
            if (rotaryEncoderVirtualPosition >= 60) {
              rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + rotaryEncoderMultiStep);
            }
            else {
              rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + rotaryEncoderSingleStep);
            }
165 166
          }
          else {
167 168
            if (rotaryEncoderVirtualPosition == rotaryEncoderMinPosition) {
              rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + 60);
169 170
            }
            else {
171 172 173 174 175 176
              if (rotaryEncoderVirtualPosition >= (60 + rotaryEncoderMultiStep)) {
                rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition - rotaryEncoderMultiStep);
              }
              else {
                rotaryEncoderVirtualPosition = rotaryEncoderVirtualPosition - rotaryEncoderSingleStep;
              }
177 178
            }
          }
179
          if (rotaryEncoderVirtualPosition > rotaryEncoderMaxPosition) {
180
            rotaryEncoderVirtualPosition = rotaryEncoderMaxPosition;
181 182
          }
          if (rotaryEncoderVirtualPosition < rotaryEncoderMinPosition) {
183
            rotaryEncoderVirtualPosition = rotaryEncoderMinPosition;
184 185 186
          }

          break;
187
        }
188

189 190
      // Input of rotary encoder controling generic integer variables within a range between rotaryEncoderMinPosition and rotaryEncoderMaxPosition
      case eRotaryEncoderMode_Generic: {
191 192 193 194 195 196 197
          if (!digitalRead(ROTARY_ENCODER_DT_PIN)) {
            rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + rotaryEncoderSingleStep);
          }
          else {
            rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition - rotaryEncoderSingleStep);
          }
          if (rotaryEncoderVirtualPosition > rotaryEncoderMaxPosition) {
service-config's avatar
Mixer  
service-config committed
198
            rotaryEncoderVirtualPosition = rotaryEncoderMaxPosition;
199 200
          }
          if (rotaryEncoderVirtualPosition < rotaryEncoderMinPosition) {
201
            rotaryEncoderVirtualPosition = rotaryEncoderMinPosition;
202 203 204
          }

          break;
service-config's avatar
Mixer  
service-config committed
205
        }
206
      default: {
207 208

        }
209
    }
210

João Lino's avatar
João Lino committed
211 212
    repaint = true;
    refresh = true;
213 214 215
  }
}

216
void xSetupRotaryEncoder( eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep ) {
217 218 219 220 221 222
  if ( newMode >= 0 ) rotaryEncoderMode = newMode;
  if ( newPosition >= 0 ) rotaryEncoderVirtualPosition = newPosition;
  if ( newMaxPosition >= 0 ) rotaryEncoderMaxPosition = newMaxPosition;
  if ( newMinPosition >= 0 ) rotaryEncoderMinPosition = newMinPosition;
  if ( newSingleStep >= 0 ) rotaryEncoderSingleStep = newSingleStep;
  if ( newMultiStep >= 0 ) rotaryEncoderMultiStep = newMultiStep;
223 224
}

225
// ######################### START #########################
226
void xSafeHardwarePowerOff() {
227
  // Turn off gracefully
João Lino's avatar
João Lino committed
228 229
  pump.shutDown();
/*
João Lino's avatar
João Lino committed
230
  iPumpSpeed = PUMP_SPEED_STOP_MOSFET;
231
  xRegulatePumpSpeed();
João Lino's avatar
João Lino committed
232
*/
233 234

  // Force shutdown
João Lino's avatar
João Lino committed
235
//  analogWrite(PUMP_PIN, PUMP_SPEED_STOP_MOSFET);  // analogWrite values from 0 to 255
236 237 238
  heatingElement.shutDown();                      // Turn heading element OFF for safety
  //digitalWrite(HEATING_ELEMENT_OUTPUT_PIN, LOW);  // Turn heading element OFF for safety
  //bStatusElement = false;
João Lino's avatar
Rel.3  
João Lino committed
239

João Lino's avatar
João Lino committed
240 241 242
  basePT100.setPumpStatus( false );
  upPT100.setPumpStatus( false );
  downPT100.setPumpStatus( false );
243

João Lino's avatar
Rel.3  
João Lino committed
244
  //analogWrite(MIXER_PIN, 0);        // Turn mixer OFF for safety
245 246
}

João Lino's avatar
Rel.3  
João Lino committed
247 248 249
void xWelcomeUser() {
  //#ifndef DEBUG
  lcdPrint(&lcd, "  Let's start", "    Brewing!");    // Write welcome
250

251 252 253
  // Play Melody;
  sing(MELODY_SUPER_MARIO_START, PIEZO_PIN);

254
  //termometerCalibration();
João Lino's avatar
João Lino committed
255
  delay(SETTING_WELCOME_TIMEOUT);      // pause for effect
João Lino's avatar
Rel.3  
João Lino committed
256
  //#endif
257 258
}

259 260
const char *_dialogs[] = {"", "b"};

261
void setup() {
João Lino's avatar
João Lino committed
262
  // ++++++++++++++++++++++++ Rotary Encoder ++++++++++++++++++++++++
263
  pinMode                         (ROTARY_ENCODER_CLK_PIN, INPUT);
João Lino's avatar
João Lino committed
264 265 266 267 268
  pinMode                         (ROTARY_ENCODER_DT_PIN, INPUT);
  pinMode                         (ROTARY_ENCODER_SW_PIN, INPUT);
  attachInterrupt                 (ROTARY_ENCODER_INTERRUPT_NUMBER, isr, FALLING);

  // ++++++++++++++++++++++++ Heating Element Relay ++++++++++++++++++++++++
269
  /*
João Lino's avatar
João Lino committed
270 271
  pinMode                         (HEATING_ELEMENT_OUTPUT_PIN, OUTPUT);
  digitalWrite                    (HEATING_ELEMENT_OUTPUT_PIN, LOW);
João Lino's avatar
Rel.3  
João Lino committed
272
  bStatusElement              =   false;
João Lino's avatar
João Lino committed
273 274
  windowStartTime             =   millis();
  dWattPerPulse               =   HEATING_ELEMENT_MAX_WATTAGE / HEATING_ELEMENT_AC_FREQUENCY_HZ;
João Lino's avatar
João Lino committed
275
  dWattage                    =   0.0;
276
  */
João Lino's avatar
João Lino committed
277 278 279
#ifdef HEATING_ELEMENT_ALWAYS_OFF
  heatingElement.setTesting(true);
#endif
João Lino's avatar
João Lino committed
280 281 282

  // ++++++++++++++++++++++++ Mixer ++++++++++++++++++++++++

283
  // ++++++++++++++++++++++++ Pump ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
284 285
  //float (Temperature::*xCheckTemperature)();
  //xCheckTemperature = &(basePT100.getCurrentTemperature);
João Lino's avatar
João Lino committed
286 287 288 289

#ifdef PUMP_ALWAYS_OFF
  pump.setTesting(true);
#endif
João Lino's avatar
João Lino committed
290 291
  pump.setCheckTemperatureFunction(&basePT100);
  /*
292
  pinMode(PUMP_PIN, OUTPUT);   // sets the pin as output
João Lino's avatar
João Lino committed
293
  iPumpSpeed                  =   PUMP_SPEED_STOP_MOSFET;             // Time frame to operate in
294
  analogWrite(PUMP_PIN, iPumpSpeed);  // analogWrite values from 0 to 255
João Lino's avatar
João Lino committed
295
  */
296

João Lino's avatar
João Lino committed
297
  // ++++++++++++++++++++++++ Piezo ++++++++++++++++++++++++
298 299
  pinMode(PIEZO_PIN, OUTPUT);

João Lino's avatar
João Lino committed
300
  // ++++++++++++++++++++++++ Temperature Sensor PT100 ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
301

João Lino's avatar
João Lino committed
302 303 304 305 306
  // ++++++++++++++++++++++++ Serial Monitor ++++++++++++++++++++++++
  Serial.begin                    (SETTING_SERIAL_MONITOR_BAUD_RATE);    // setup terminal baud rate
  Serial.println                  (SETTING_SERIAL_MONITOR_WELCOME_MESSAGE);  // print a start message to the terminal

  // ++++++++++++++++++++++++ Library - LiquidCrystal_I2C ++++++++++++++++++++++++
307 308
  lcd.begin                       (LCD_HORIZONTAL_RESOLUTION, LCD_VERTICAL_RESOLUTION);   //  <<----- My LCD was 16x2
  lcd.setBacklightPin             (LCD_BACKLIGHT_PIN, POSITIVE);       // Setup backlight pin
João Lino's avatar
João Lino committed
309 310 311 312 313 314
  lcd.setBacklight                (HIGH);              // Switch on the backlight

  // ######################### INITIALIZE #########################
  // ++++++++++++++++++++++++ Rotary Encoder ++++++++++++++++++++++++
  // set operation state | INPUT : eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep
  xSetupRotaryEncoder             ( eRotaryEncoderMode_Disabled, 0, 0, 0, 0, 0 );
João Lino's avatar
João Lino committed
315
  rotarySwDetectTime = 0;
João Lino's avatar
João Lino committed
316 317

  // ++++++++++++++++++++++++ State Machine ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
318
  eMenuType                   =   MENU_INIT;
João Lino's avatar
João Lino committed
319

João Lino's avatar
João Lino committed
320 321 322 323
  cookingStage                =   SETTING_COOKING_STAGE_INIT;
  beerProfile                 =   SETTING_BEER_PROFILE_INIT;

  cancel                      =   false;
João Lino's avatar
João Lino committed
324
  // ++++++++++++++++++++++++ Global Variables ++++++++++++++++++++++++
João Lino's avatar
Rel.3  
João Lino committed
325

João Lino's avatar
João Lino committed
326
  cooking                     =   false;
327

João Lino's avatar
João Lino committed
328
  clockStartTime              =   0;
João Lino's avatar
Rel.3  
João Lino committed
329
  clockLastUpdate             =   0;
João Lino's avatar
João Lino committed
330 331 332 333
  clockCounter                =   0;
  clockIgnore                 =   0;
  clockStart                  =   false;
  clockEnd                    =   false;
334

João Lino's avatar
João Lino committed
335 336
  cookTime                    =   3600;
  cookTemperature             =   25;
João Lino's avatar
João Lino committed
337
  finalYield                  =   SETTING_MACHINE_YIELD_DEFAULT;
João Lino's avatar
João Lino committed
338

339 340 341 342 343 344 345 346 347 348 349
  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;
João Lino's avatar
Rel.3  
João Lino committed
350
  cleaningTime                =   SETTING_CLEANING_TIME;
João Lino's avatar
João Lino committed
351

352 353 354 355 356 357 358 359 360 361 362
  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;
João Lino's avatar
Rel.3  
João Lino committed
363
  cleaningTemperature         =   SETTING_CLEANING_TEMPERATURE;
João Lino's avatar
João Lino committed
364 365 366 367

  refresh                     =   true;
  repaint                     =   true;

João Lino's avatar
João Lino committed
368 369
  loggingTimeInterval         =   0;

João Lino's avatar
João Lino committed
370 371 372 373
  // ++++++++++++++++++++++++ Interrupts ++++++++++++++++++++++++
  lastInterruptTime           =   0;

  // ++++++++++++++++++++++++ PID  ++++++++++++++++++++++++
374
  //iWindowSize                 =   HEATING_ELEMENT_DEFAULT_WINDOW_SIZE;    // Time frame to operate in
375

João Lino's avatar
Rel.3  
João Lino committed
376
  // ######################### Code - Run Once #########################
João Lino's avatar
João Lino committed
377
  xSafeHardwarePowerOff           ();
João Lino's avatar
Rel.3  
João Lino committed
378
  xWelcomeUser                    ();
379

João Lino's avatar
Rel.3  
João Lino committed
380
  xSetupRotaryEncoder             ( eRotaryEncoderMode_Menu, eMainMenu_GO, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );
381 382

  printBeerProfile();
383
}
384

385
// ######################### MAIN LOOP #########################
386 387

void loop() {
João Lino's avatar
João Lino committed
388
  unsigned long inactivityTime = getInactivityTime();
389

390 391
  if ( inactivityTime > SETTING_MAX_INACTIVITY_TIME ) {   // Inactivity check
    if (refresh) {
392 393 394
      repaint = true;
      refresh = false;
    }
João Lino's avatar
Rel.3  
João Lino committed
395
    repaint = displayStatus( &lcd, cooking, cookTemperature, basePT100.getCurrentTemperature(), upPT100.getCurrentTemperature(), downPT100.getCurrentTemperature(), clockCounter, repaint );
396 397
  }
  else {
João Lino's avatar
Rel.3  
João Lino committed
398
    runMenu();
399
  }
400

João Lino's avatar
Rel.3  
João Lino committed
401
  xManageMachineSystems();
402 403
}

404 405
// ######################### FUNCTIONS ########################

João Lino's avatar
João Lino committed
406
void xCountTheTime( float temperatureMarginRange, boolean bMaximumOfUpDown ) {
João Lino's avatar
João Lino committed
407
  unsigned long now = millis();
João Lino's avatar
João Lino committed
408

João Lino's avatar
João Lino committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422
  // 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();
  }
João Lino's avatar
João Lino committed
423

João Lino's avatar
João Lino committed
424
  // Ignote time ticks if temperature is not within the acceptable margin for this stage
425
  unsigned long lastWindowTime = now - clockLastUpdate;
João Lino's avatar
João Lino committed
426
  if ( temperatureCount < (cookTemperature - temperatureMarginRange) ) {
427
    clockIgnore += lastWindowTime;
João Lino's avatar
João Lino committed
428
  }
João Lino's avatar
João Lino committed
429

João Lino's avatar
João Lino committed
430
  // Calculate the remaining time on the clock
431 432 433
  //clockCounter = cookTime * 1000 - (lastWindowTime - clockIgnore);
  unsigned long elepsedTime = now - clockStartTime;
  clockCounter = cookTime * 1000 - (elepsedTime - clockIgnore);
434

João Lino's avatar
João Lino committed
435 436 437 438
  // Don't let clock get bellow 0
  if ( clockCounter < 0 ) {
    clockCounter = 0;
  }
João Lino's avatar
João Lino committed
439

João Lino's avatar
João Lino committed
440
  clockLastUpdate = now;
João Lino's avatar
João Lino committed
441

João Lino's avatar
João Lino committed
442 443 444 445 446 447 448 449 450
#ifdef DEBUG_OFF
  debugPrintFunction("xCountTheTime");
  debugPrintVar("millis()", now);
  debugPrintVar("cookTime", cookTime);
  debugPrintVar("clockStartTime", clockStartTime);
  debugPrintVar("clockIgnore", clockIgnore);
  debugPrintVar("clockCounter", clockCounter);
#endif
}
451

João Lino's avatar
João Lino committed
452 453 454 455 456 457
bool isTimeLeft() {
  if ( clockCounter > 0 ) {
    return true;
  }
  return false;
}
João Lino's avatar
João Lino committed
458

459
/*
João Lino's avatar
João Lino committed
460 461 462 463 464
//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;
}
465
*/
466

João Lino's avatar
João Lino committed
467 468 469
bool xRegulateTemperature( boolean bMaximumOfUpDown ) {
  double difference = 0;
  bool overTemperature = false;
470
  //double dWattage = 0.0;
471

João Lino's avatar
João Lino committed
472 473 474
  float tup = upPT100.getCurrentTemperature();
  float tdown = downPT100.getCurrentTemperature();
  float tbase = basePT100.getCurrentTemperature();
475

João Lino's avatar
João Lino committed
476 477 478 479 480 481 482
  if ( bMaximumOfUpDown ) {
    if (tup > tdown) {
      difference = cookTemperature - tup;
    }
    else {
      difference = cookTemperature - tdown;
    }
483

João Lino's avatar
João Lino committed
484 485 486
    if (tbase > cookTemperature && (tbase >= (PUMP_TEMPERATURE_MAX_OPERATION - 2.0) || difference >= 5.0)) {
      difference = cookTemperature - tbase;
    }
487

João Lino's avatar
João Lino committed
488 489 490 491 492 493
    if ( (tbase < cookTemperature) && (difference < (cookTemperature - tbase)) ) {
      difference = cookTemperature - tbase;
    }
  } else {
    difference = cookTemperature - tbase;
  }
494

João Lino's avatar
João Lino committed
495 496 497 498 499
  // Deviation between the cook temperature set and the cook temperature measured
  if ( difference < 0.0 ) {
    difference = difference * (-1.0);
    overTemperature = true;
  }
500

João Lino's avatar
João Lino committed
501 502
  // Calculate applied wattage, based on the distance from the target temperature
  if ( overTemperature ) {
503 504
    //dWattage = 0.0;                      // turn it off
    heatingElement.setWattage(heatingElement.getNullWattage());             // turn it off
João Lino's avatar
João Lino committed
505 506 507 508
  }
  else {
    if ( difference <= 0.5 ) {
      if ( cookTemperature > 99.0 ) {
509 510
        //dWattage = 2000.0;               // pulse hardly at 2000 watt
        heatingElement.setWattage(heatingElement.getTwoThirdWattage());             // pulse hardly at 2000 watt
João Lino's avatar
João Lino committed
511 512
      }
      else {
João Lino's avatar
João Lino committed
513
        if ( cookTemperature > 70.0 ) {
514 515
          //dWattage = 1000.0;             // pulse moderately at 1000 watt
          heatingElement.setWattage(heatingElement.getOneThirdWattage());             // pulse moderately at 1000 watt
João Lino's avatar
João Lino committed
516 517
        }
        else {
518 519
          //dWattage = 500.0;              // pulse lightly at 500 watt
          heatingElement.setWattage(heatingElement.getOneSixthWattage());             // pulse lightly at 500 watt
520
        }
João Lino's avatar
Rel.3  
João Lino committed
521
      }
João Lino's avatar
João Lino committed
522 523 524 525
    }
    else {
      if ( difference <= 1.0 ) {
        if ( cookTemperature > 99.0 ) {
526 527
          //dWattage = 2000.0;             // pulse hardly at 2000 watt
          heatingElement.setWattage(heatingElement.getTwoThirdWattage());             // pulse hardly at 2000 watt
João Lino's avatar
João Lino committed
528 529
        }
        else {
530 531
          //dWattage = 1000.0;             // pulse moderately at 1000 watt
          heatingElement.setWattage(heatingElement.getOneThirdWattage());             // pulse moderately at 1000 watt
João Lino's avatar
João Lino committed
532
        }
João Lino's avatar
João Lino committed
533 534 535
      }
      else {
        if ( difference <= 3.0 ) {
536 537
          //dWattage = 2000.0;             // pulse hardly at 2000 watt
          heatingElement.setWattage(heatingElement.getTwoThirdWattage());             // pulse hardly at 2000 watt
João Lino's avatar
João Lino committed
538 539
        }
        else {
540 541
          //dWattage = HEATING_ELEMENT_MAX_WATTAGE;  // pulse constantly at HEATING_ELEMENT_MAX_WATTAGE watt
          heatingElement.setWattage(heatingElement.getMaxWattage());  // pulse constantly at HEATING_ELEMENT_MAX_WATTAGE watt
542
        }
João Lino's avatar
João Lino committed
543 544 545
      }
    }
  }
546

547 548 549 550
  // Update the recorded time for the begining of the window, if the previous window has passed. Then apply wattage to the element at the right time
  heatingElement.process();
  
  /*
João Lino's avatar
João Lino committed
551 552 553 554
  // 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;
  }
555
  
João Lino's avatar
João Lino committed
556
  // Apply wattage to the element at the right time
João Lino's avatar
João Lino committed
557
  if ( ulWattToWindowTime( dWattage ) > (millis() - windowStartTime) ) {
João Lino's avatar
João Lino committed
558 559 560 561 562
    digitalWrite(HEATING_ELEMENT_OUTPUT_PIN, HIGH);
    bStatusElement = true;
  } else {
    digitalWrite(HEATING_ELEMENT_OUTPUT_PIN, LOW);
    bStatusElement = false;
563
  }
564
  */
João Lino's avatar
Rel.3  
João Lino committed
565

566
#ifdef DEBUG_OFF
João Lino's avatar
João Lino committed
567 568 569
  //debugPrintFunction("xRegulateTemperature");
  debugPrintVar("difference", difference);
  //debugPrintVar("overTemperature", overTemperature);
570
  debugPrintVar("dWattage", heatingElement.getWattage());
João Lino's avatar
João Lino committed
571
  //debugPrintVar("ulWattToWindowTime( dWattage )", ulWattToWindowTime( dWattage ) );
João Lino's avatar
João Lino committed
572 573
  //debugPrintVar("millis()", millis());
  //debugPrintVar("windowStartTime", windowStartTime);
João Lino's avatar
João Lino committed
574
  //debugPrintVar("test", ulWattToWindowTime( dWattage ) > (millis() - windowStartTime) );
575
#endif
576 577
}

João Lino's avatar
João Lino committed
578
void xPurgePump() {
579
  lcdPrint(&lcd, "    Purging", "     Pump!");    // Write welcome
João Lino's avatar
João Lino committed
580 581
  pump.forcePumpSelfPrime();
  /*
João Lino's avatar
João Lino committed
582 583 584 585 586 587
  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);
  }
João Lino's avatar
João Lino committed
588
  */
João Lino's avatar
João Lino committed
589
}
João Lino's avatar
Rel.3  
João Lino committed
590

João Lino's avatar
João Lino committed
591
bool xRegulatePumpSpeed() {
João Lino's avatar
João Lino committed
592 593 594 595 596 597 598 599
  pump.process();
  
  bool isPumpOn = pump.isPumpOn();
  basePT100.setPumpStatus( isPumpOn );
  upPT100.setPumpStatus( isPumpOn );
  downPT100.setPumpStatus( isPumpOn );

  /*
João Lino's avatar
João Lino committed
600 601 602 603 604 605 606 607 608 609
  if(pump.process()) {
    basePT100.setPumpStatus( true );
    upPT100.setPumpStatus( true );
    downPT100.setPumpStatus( true );
  }
  else{
    basePT100.setPumpStatus( false );
    upPT100.setPumpStatus( false );
    downPT100.setPumpStatus( false );
  }
João Lino's avatar
João Lino committed
610
  
João Lino's avatar
João Lino committed
611
  //  analogWrite(PUMP_PIN, iPumpSpeed);  // analogWrite values from 0 to 255
João Lino's avatar
João Lino committed
612 613
  if (basePT100.getCurrentTemperature() > PUMP_TEMPERATURE_MAX_OPERATION) {
    analogWrite(PUMP_PIN, PUMP_SPEED_STOP_MOSFET);  // analogWrite values from 0 to 255
João Lino's avatar
Rel.3  
João Lino committed
614

João Lino's avatar
João Lino committed
615 616 617 618 619 620
    basePT100.setPumpStatus( false );
    upPT100.setPumpStatus( false );
    downPT100.setPumpStatus( false );
  }
  else {
    analogWrite(PUMP_PIN, iPumpSpeed);  // analogWrite values from 0 to 255
621

João Lino's avatar
João Lino committed
622 623 624
    basePT100.setPumpStatus( true );
    upPT100.setPumpStatus( true );
    downPT100.setPumpStatus( true );
João Lino's avatar
Rel.3  
João Lino committed
625
  }
João Lino's avatar
João Lino committed
626
  */
João Lino's avatar
João Lino committed
627
}
João Lino's avatar
Rel.3  
João Lino committed
628

João Lino's avatar
João Lino committed
629 630
void xWarnClockEnded() {
  sing(MELODY_SUPER_MARIO_START, PIEZO_PIN);
João Lino's avatar
Rel.3  
João Lino committed
631 632
}

João Lino's avatar
João Lino committed
633 634 635
void xWarnCookEnded() {
  sing(MELODY_UNDERWORLD_SHORT, PIEZO_PIN);
}
João Lino's avatar
Rel.3  
João Lino committed
636

João Lino's avatar
João Lino committed
637 638 639 640 641
void xPrepareForStage( int stageTime, int stageTemperature, int stagePumpSpeed, eCookingStages stage ) {
#ifdef DEBUG_OFF
  debugPrintFunction("xPrepareForStage");
  debugPrintVar("cookingStage", stage);
#endif
642

João Lino's avatar
João Lino committed
643 644 645 646 647
  // Reset the clock
  unsigned long now = millis();
  clockStartTime  = now;
  clockLastUpdate = now;
  clockIgnore     = 0;
João Lino's avatar
Rel.3  
João Lino committed
648

João Lino's avatar
João Lino committed
649 650
  pump.setTargetPumpSpeed(stagePumpSpeed);  // Set the pump speed
  //iPumpSpeed      = stagePumpSpeed;         // Set the pump speed
João Lino's avatar
João Lino committed
651 652 653
  cookingStage    = stage;                  // Set Stage
  cookTime        = stageTime;              // Set the clock
  cookTemperature = stageTemperature;       // Set the target temperature
João Lino's avatar
Rel.3  
João Lino committed
654 655
}

João Lino's avatar
João Lino committed
656 657 658 659 660
void xSetupStage(eCookingStages nextStage) {
#ifdef DEBUG_OFF
  debugPrintFunction("xSetupStage");
  debugPrintVar("cookingStage", nextStage);
#endif
João Lino's avatar
Rel.3  
João Lino committed
661

João Lino's avatar
João Lino committed
662 663 664 665 666 667 668 669 670 671 672 673
  // 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.");
674

João Lino's avatar
João Lino committed
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
              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.");
693

João Lino's avatar
João Lino committed
694 695 696 697 698
              xWaitForAction("Malt", say);
              repaint = true;
              break;
            }
          default: {
João Lino's avatar
Rel.3  
João Lino committed
699

João Lino's avatar
João Lino committed
700 701
            }
        }
702

João Lino's avatar
João Lino committed
703 704
        // Make sure there is water
        xWaitForAction("Water", "Make sure there is water in the machine before start cooking.");
705

João Lino's avatar
João Lino committed
706
        repaint = true;
João Lino's avatar
João Lino committed
707
        xPrepareForStage( startpointTime, startpointTemperature, pump.getMaxSpeed(), eCookingStage_Startpoint );
708 709
        break;
      }
João Lino's avatar
João Lino committed
710 711 712 713 714 715 716 717 718 719
    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.");
720

João Lino's avatar
João Lino committed
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
              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.");
739

João Lino's avatar
João Lino committed
740 741 742 743 744 745
              xWaitForAction("Malt", say);
              repaint = true;
              break;
            }
          default: {}
        }
João Lino's avatar
João Lino committed
746
        xPrepareForStage( betaGlucanaseTime, betaGlucanaseTemperature, pump.getMaxSpeed(), eCookingStage_BetaGlucanase );
747 748
        break;
      }
João Lino's avatar
João Lino committed
749
    case eCookingStage_Debranching: {
João Lino's avatar
João Lino committed
750
        xPrepareForStage( debranchingTime, debranchingTemperature, pump.getMaxSpeed(), eCookingStage_Debranching );
751 752
        break;
      }
João Lino's avatar
João Lino committed
753
    case eCookingStage_Proteolytic: {
João Lino's avatar
João Lino committed
754
        xPrepareForStage( proteolyticTime, proteolyticTemperature, pump.getMaxSpeed(), eCookingStage_Proteolytic );
755 756
        break;
      }
João Lino's avatar
João Lino committed
757
    case eCookingStage_BetaAmylase: {
João Lino's avatar
João Lino committed
758
        xPrepareForStage( betaAmylaseTime, betaAmylaseTemperature, pump.getMaxSpeed(), eCookingStage_BetaAmylase );
759 760
        break;
      }
João Lino's avatar
João Lino committed
761
    case eCookingStage_AlphaAmylase: {
João Lino's avatar
João Lino committed
762
        xPrepareForStage( alphaAmylaseTime, alphaAmylaseTemperature, pump.getMaxSpeed(), eCookingStage_AlphaAmylase );
763 764
        break;
      }
João Lino's avatar
João Lino committed
765
    case eCookingStage_Mashout: {
João Lino's avatar
João Lino committed
766
        xPrepareForStage( mashoutTime, mashoutTemperature, pump.getMaxSpeed(), eCookingStage_Mashout );
767 768
        break;
      }
João Lino's avatar
João Lino committed
769 770 771
    case eCookingStage_Recirculation: {
        xWaitForAction("Sparge Water", "Start heating your sparge water.");
        repaint = true;
João Lino's avatar
João Lino committed
772
        xPrepareForStage( recirculationTime, recirculationTemperature, pump.getMaxSpeed(), eCookingStage_Recirculation );
773 774
        break;
      }
João Lino's avatar
João Lino committed
775 776 777
    case eCookingStage_Sparge: {
        xWaitForAction("Sparge Water", "Start pouring the sparge water.");
        repaint = true;
João Lino's avatar
João Lino committed
778
        xPrepareForStage( spargeTime, spargeTemperature, pump.getMaxSpeed(), eCookingStage_Sparge );
779 780
        break;
      }
João Lino's avatar
João Lino committed
781 782 783 784
    case eCookingStage_Boil: {
        switch (beerProfile) {
          case eBeerProfile_Trigo: {
              String say = "Get ";
785

João Lino's avatar
João Lino committed
786 787
              float hopAmount = 0.8 * ((float) finalYield);
              say += String(hopAmount);
788

João Lino's avatar
João Lino committed
789
              say += String("g of Magnum 9.4\% and Styrian Golding 5\% ready.");
João Lino's avatar
Rel.3  
João Lino committed
790

João Lino's avatar
João Lino committed
791
              xWaitForAction("Hops", say);
792

João Lino's avatar
João Lino committed
793 794 795 796
              break;
            }
          case eBeerProfile_IPA: {
              String say = "Get ";
João Lino's avatar
Rel.3  
João Lino committed
797

João Lino's avatar
João Lino committed
798 799
              float hopAmount = 0.8 * ((float) finalYield);
              say += String(hopAmount);
João Lino's avatar
Rel.3  
João Lino committed
800

João Lino's avatar
João Lino committed
801
              say += String("g of Chinook, Cascade and Styrian Golding ready.");
802

João Lino's avatar
João Lino committed
803
              xWaitForAction("Hops", say);
804

João Lino's avatar
João Lino committed
805 806 807 808
              break;
            }
          default: {
              xWaitForAction("Hops", "Add the hops in the right order, at the right time.");
809

João Lino's avatar
João Lino committed
810 811
            }
        }
812

João Lino's avatar
João Lino committed
813
        repaint = true;
814

João Lino's avatar
João Lino committed
815
        // A basic operation for a basic stage
João Lino's avatar
João Lino committed
816
        xPrepareForStage( boilTime, boilTemperature, pump.getMaxSpeed(), eCookingStage_Boil );
João Lino's avatar
Rel.3  
João Lino committed
817

818 819
        break;
      }
João Lino's avatar
João Lino committed
820 821 822
    case eCookingStage_Cooling: {
        // Make sure there is water
        xWaitForAction("Coil", "Add the coil and connect it to the main water supply.");
823

João Lino's avatar
João Lino committed
824 825 826
        repaint = true;

        // A basic operation for a basic stage
João Lino's avatar
João Lino committed
827
        xPrepareForStage( coolingTime, coolingTemperature, pump.getMaxSpeed(), eCookingStage_Cooling );
828 829 830

        break;
      }
João Lino's avatar
João Lino committed
831 832 833
    case eCookingStage_Clean: {
        // Make sure there is water
        xWaitForAction("Water", "Add 13 liters.");
834

João Lino's avatar
João Lino committed
835 836
        // Make sure there is water
        xWaitForAction("Star San HB", "Add 0.89oz/26ml.");
837

João Lino's avatar
João Lino committed
838
        repaint = true;
839

João Lino's avatar
João Lino committed
840
        // A basic operation for a basic stage
João Lino's avatar
João Lino committed
841
        xPrepareForStage( cleaningTime, cleaningTemperature, pump.getMaxSpeed(), eCookingStage_Clean );
842 843 844

        break;
      }
João Lino's avatar
João Lino committed
845 846
    case eCookingStage_Purge: {
        // A basic operation for a basic stage
João Lino's avatar
João Lino committed
847
        xPrepareForStage( 0, 0, pump.getMaxSpeed(), eCookingStage_Purge );
848

João Lino's avatar
João Lino committed
849
        xRegulatePumpSpeed();
850 851 852

        break;
      }
João Lino's avatar
João Lino committed
853 854
    case eCookingStage_Done: {
        // A basic operation for a basic stage
João Lino's avatar
João Lino committed
855
        xPrepareForStage( 0, 0, pump.getNullSpeed(), eCookingStage_Done );
856 857 858

        break;
      }
859
  }
860 861
}

João Lino's avatar
João Lino committed
862 863 864
void xTransitionIntoStage(eCookingStages nextStage) {
  // Turn off all hardware that can damage itself if the machine is not cooking
  xSafeHardwarePowerOff();
865

João Lino's avatar
João Lino committed
866 867 868 869 870 871 872
  // Warn the user a stage has ended
  xWarnClockEnded();

  // Reset global stage variables
  xSetupStage( nextStage );
}

João Lino's avatar
João Lino committed
873
void xBasicStageOperation( int iStageTime, int iStageTemperature, float iStageTemperatureRange, eCookingStages nextStage, boolean bMaximumOfUpDown ) {
João Lino's avatar
João Lino committed
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897

  // 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;
898
  }
João Lino's avatar
João Lino committed
899 900 901 902 903 904 905 906 907

  return;
}

void xManageMachineSystems() {
  // Measure temperature, for effect
  basePT100.measure(false);
  upPT100.measure(false);
  downPT100.measure(true);
João Lino's avatar
João Lino committed
908

909 910 911 912 913 914 915 916 917 918 919 920 921 922
#ifdef INFO
  unsigned long now = millis();
  if( now - loggingTimeInterval > SETTING_MACHINE_LOGGING_INTERVAL ) {
    loggingTimeInterval = now;
    Serial.print("|");
    Serial.print(now);
    Serial.print("|");
    if (cooking) {
      Serial.print("1");
    }
    else {
      Serial.print("0");
    }
    Serial.print("|");
João Lino's avatar
João Lino committed
923 924 925 926
    Serial.print( mdStageMenu._dialog[cookingStage+1] );
    Serial.print("|");
    Serial.print(clockCounter);
    Serial.print("|");
927 928 929 930 931 932 933 934
    Serial.print(cookTemperature);
    Serial.print("|");
    Serial.print(basePT100.getCurrentTemperature());
    Serial.print("|");
    Serial.print(upPT100.getCurrentTemperature());
    Serial.print("|");
    Serial.print(downPT100.getCurrentTemperature());
    Serial.print("|");
935
    Serial.print(heatingElement.getWattage());
João Lino's avatar
João Lino committed
936
    Serial.print("|");
937 938
//    if (bStatusElement) {
    if (heatingElement.isStatusElement()) {
939 940 941 942 943 944 945 946 947
      Serial.print("1");
    }
    else {
      Serial.print("0");
    }
    Serial.println("|");
  } 
#endif

João Lino's avatar
João Lino committed
948 949 950
  // 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();
João Lino's avatar
João Lino committed
951

João Lino's avatar
João Lino committed
952 953
    return;
  }
João Lino's avatar
João Lino committed
954

João Lino's avatar
João Lino committed
955 956 957
  // Operate the machine according to the current mode
  switch (cookingStage) {
    case eCookingStage_Startpoint: {
João Lino's avatar
João Lino committed
958
        xBasicStageOperation( startpointTime, startpointTemperature, 0.0, eCookingStage_BetaGlucanase, false);
959 960
        break;
      }
João Lino's avatar
João Lino committed
961
    case eCookingStage_BetaGlucanase: {
João Lino's avatar
João Lino committed
962
        xBasicStageOperation( betaGlucanaseTime, betaGlucanaseTemperature, 3.0, eCookingStage_Debranching, true );
963 964
        break;
      }
João Lino's avatar
João Lino committed
965
    case eCookingStage_Debranching: {
João Lino's avatar
João Lino committed
966
        xBasicStageOperation( debranchingTime, debranchingTemperature, 3.0, eCookingStage_Proteolytic, true );
967 968
        break;
      }
João Lino's avatar
João Lino committed
969
    case eCookingStage_Proteolytic: {
João Lino's avatar
João Lino committed
970
        xBasicStageOperation( proteolyticTime, proteolyticTemperature, 3.0, eCookingStage_BetaAmylase, true );
971 972
        break;
      }
João Lino's avatar
João Lino committed
973
    case eCookingStage_BetaAmylase: {
João Lino's avatar
João Lino committed
974
        xBasicStageOperation( betaAmylaseTime, betaAmylaseTemperature, 7.0, eCookingStage_AlphaAmylase, true );
975 976
        break;
      }
João Lino's avatar
João Lino committed
977
    case eCookingStage_AlphaAmylase: {
João Lino's avatar
João Lino committed
978
        xBasicStageOperation( alphaAmylaseTime, alphaAmylaseTemperature, 2.5, eCookingStage_Mashout, true );
979 980
        break;
      }
João Lino's avatar
João Lino committed
981
    case eCookingStage_Mashout: {
João Lino's avatar
João Lino committed
982
        xBasicStageOperation( mashoutTime, mashoutTemperature, 1.0, eCookingStage_Recirculation, true );
983 984
        break;
      }
João Lino's avatar
João Lino committed
985
    case eCookingStage_Recirculation: {
João Lino's avatar
João Lino committed
986
        xBasicStageOperation( recirculationTime, recirculationTemperature, 1.0, eCookingStage_Sparge, true );
987 988
        break;
      }
João Lino's avatar
João Lino committed
989
    case eCookingStage_Sparge: {
João Lino's avatar
João Lino committed
990
        xBasicStageOperation( spargeTime, spargeTemperature, 3.0, eCookingStage_Boil, false );
991 992
        break;
      }
João Lino's avatar
João Lino committed
993
    case eCookingStage_Boil: {
João Lino's avatar
João Lino committed
994
        xBasicStageOperation( boilTime, boilTemperature, 2.0, eCookingStage_Cooling, false );
995 996
        break;
      }
João Lino's avatar
João Lino committed
997
    case eCookingStage_Cooling: {
João Lino's avatar
João Lino committed
998
        xBasicStageOperation( coolingTime, coolingTemperature, 0.0, eCookingStage_Done, false );
999 1000
        break;
      }
João Lino's avatar
João Lino committed
1001
    case eCookingStage_Clean: {
João Lino's avatar
João Lino committed
1002
        xBasicStageOperation( cleaningTime, cleaningTemperature, 0.0, eCookingStage_Done, false );
1003 1004
        break;
      }
João Lino's avatar
João Lino committed
1005
    case eCookingStage_Purge: {
João Lino's avatar
João Lino committed
1006 1007
        pump.process(pump.getMaxSpeed());
        /*
João Lino's avatar
João Lino committed
1008 1009
        iPumpSpeed = PUMP_SPEED_MAX_MOSFET;
        xRegulatePumpSpeed();
João Lino's avatar
João Lino committed
1010
        */
João Lino's avatar
João Lino committed
1011 1012
        break;
      }
João Lino's avatar
João Lino committed
1013
    case eCookingStage_Done: {
João Lino's avatar
João Lino committed
1014 1015 1016 1017 1018 1019
        stopBrewing();                  // Update cooking state
        repaint = true;                 // Ask for screen refresh
        xWarnCookEnded();               // Warn the user that the cooking is done
        break;
      }
  }
João Lino's avatar
João Lino committed
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
}

// ##################################################### 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: {
João Lino's avatar
João Lino committed
1038 1039 1040
        runMenuProcessor( &mdMainMenu );
        break;
      }
João Lino's avatar
João Lino committed
1041
    case eMenuType_BeerProfile: {
João Lino's avatar
João Lino committed
1042 1043 1044
        runMenuProcessor( &mdBeerProfileMenu );
        break;
      }
João Lino's avatar
João Lino committed
1045
    case eMenuType_Stage: {
João Lino's avatar
João Lino committed
1046 1047 1048
        runMenuProcessor( &mdStageMenu );
        break;
      }
João Lino's avatar
João Lino committed
1049
    case eMenuType_Malt: {
João Lino's avatar
João Lino committed
1050 1051 1052
        runMenuProcessor( &mdMaltMenu );
        break;
      }
João Lino's avatar
João Lino committed
1053
    case eMenuType_Settings: {
João Lino's avatar
João Lino committed
1054 1055 1056
        runMenuProcessor( &mdSettingsMenu );
        break;
      }
João Lino's avatar
João Lino committed
1057
    case eMenuType_StartFromStage: {
João Lino's avatar
João Lino committed
1058 1059 1060
        runMenuProcessor( &mdStartFromStageMenu );
        break;
      }
João Lino's avatar
João Lino committed
1061 1062 1063 1064 1065
  }

#ifdef DEBUG_OFF
  if (debug_go) {
    debugPrintVar("repaint", repaint);
João Lino's avatar
João Lino committed
1066
  }
João Lino's avatar
João Lino committed
1067
#endif
João Lino's avatar
João Lino committed
1068 1069
}

João Lino's avatar
João Lino committed
1070
// ************************ MENU SELECTIONS ******************************
João Lino's avatar
Rel.3  
João Lino committed
1071
void runMainMenuSelection() {
1072
  switch (mdMainMenu._selection) {
João Lino's avatar
João Lino committed
1073
    //switch (eMainMenuSelection) {
João Lino's avatar
João Lino committed
1074
    case eMainMenu_GO: {
1075 1076 1077
        xStartStage( NULL, NULL, eCookingStage_Startpoint, true, true, false, false );
        break;
      }
João Lino's avatar
João Lino committed
1078
    case eMainMenu_GO_FROM_STAGE: {
1079 1080
        eMenuType = eMenuType_StartFromStage;
        repaint = true;
João Lino's avatar
João Lino committed
1081
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdBeerProfileMenu._position, MENU_SIZE_PROFILES_MENU - 1, 1, 1, 0 );
1082 1083
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1084
    case eMainMenu_STOP: {
1085 1086 1087 1088
        stopBrewing();
        backToStatus();
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1089
    case eMainMenu_SKIP: {
1090 1091 1092 1093
        cookTime = 0;
        backToStatus();
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1094
    case eMainMenu_BeerProfile: {
1095 1096
        eMenuType = eMenuType_BeerProfile;
        repaint = true;
João Lino's avatar
João Lino committed
1097
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdBeerProfileMenu._position, MENU_SIZE_PROFILES_MENU - 1, 1, 1, 0 );
1098 1099 1100 1101 1102
        break;
      }
    case eMainMenu_Stage: {
        eMenuType = eMenuType_Stage;
        repaint = true;
João Lino's avatar
João Lino committed
1103
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdStageMenu._position, MENU_SIZE_STAGE_MENU - 1, 1, 1, 0 );
1104 1105
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1106
    case eMainMenu_Malt: {
1107 1108
        eMenuType = eMenuType_Malt;
        repaint = true;
João Lino's avatar
João Lino committed
1109
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMaltMenu._position, MENU_SIZE_MALT_MENU - 1, 1, 1, 0 );
1110 1111
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1112
    case eMainMenu_Hops: {
1113 1114 1115
        backToStatus();
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1116
    case eMainMenu_Clean: {
1117 1118 1119
        xStartStageHeadless( eCookingStage_Clean, true );
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1120
    case eMainMenu_Purge: {
1121 1122 1123
        xStartStageHeadless( eCookingStage_Purge, true );
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1124
    case eMainMenu_Settings: {
1125 1126
        eMenuType = eMenuType_Settings;
        repaint = true;
João Lino's avatar
João Lino committed
1127
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdSettingsMenu._position, MENU_SIZE_SETTINGS_MENU - 1, 1, 1, 0 );
1128 1129
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1130
    case eMainMenu_Back: {
1131 1132 1133
        backToStatus();
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1134
    default: {
1135
      }
João Lino's avatar
Rel.3  
João Lino committed
1136
  }
1137
  mdMainMenu._selection = eMainMenu_NULL;
1138 1139
}

João Lino's avatar
João Lino committed
1140

João Lino's avatar
João Lino committed
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
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: {
      }
João Lino's avatar
João Lino committed
1193
  }
João Lino's avatar
João Lino committed
1194 1195
  mdStartFromStageMenu._selection = eStageMenu_NULL;
}
1196

João Lino's avatar
João Lino committed
1197 1198 1199
void runBeerProfileSelection() {
  switch (mdBeerProfileMenu._selection) {
    case eBeerProfileMenu_Basic: {
João Lino's avatar
João Lino committed
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
        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;

1224
        printBeerProfile();
João Lino's avatar
João Lino committed
1225 1226 1227
        backToStatus();
        break;
      }
João Lino's avatar
João Lino committed
1228
    case eBeerProfileMenu_Trigo: {
João Lino's avatar
João Lino committed
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
        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;
João Lino's avatar
João Lino committed
1252

1253
        printBeerProfile();
João Lino's avatar
João Lino committed
1254 1255 1256
        backToStatus();
        break;
      }
João Lino's avatar
João Lino committed
1257
    case eBeerProfileMenu_IPA: {
João Lino's avatar
João Lino committed
1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
        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;
João Lino's avatar
João Lino committed
1281

1282
        printBeerProfile();
João Lino's avatar
João Lino committed
1283 1284 1285
        backToStatus();
        break;
      }
João Lino's avatar
João Lino committed
1286
    case eBeerProfileMenu_Belga: {
João Lino's avatar
João Lino committed
1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
        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;
João Lino's avatar
João Lino committed
1310

1311
        printBeerProfile();
João Lino's avatar
João Lino committed
1312 1313 1314
        backToStatus();
        break;
      }
João Lino's avatar
João Lino committed
1315
    case eBeerProfileMenu_Red: {
João Lino's avatar
João Lino committed
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338
        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;
1339 1340
        
        printBeerProfile();
João Lino's avatar
João Lino committed
1341 1342 1343
        backToStatus();
        break;
      }
João Lino's avatar
João Lino committed
1344
    case eBeerProfileMenu_APA: {
João Lino's avatar
João Lino committed
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367
        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;
João Lino's avatar
João Lino committed
1368

1369
        printBeerProfile();
João Lino's avatar
João Lino committed
1370 1371 1372
        backToStatus();
        break;
      }
João Lino's avatar
João Lino committed
1373
    case eBeerProfileMenu_Custom: {
João Lino's avatar
João Lino committed
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396
        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;
João Lino's avatar
João Lino committed
1397

1398
        printBeerProfile();
João Lino's avatar
João Lino committed
1399 1400 1401
        backToStatus();
        break;
      }
João Lino's avatar
João Lino committed
1402
    case eBeerProfileMenu_Back: {
João Lino's avatar
João Lino committed
1403 1404 1405
        resetMenu( true );
        break;
      }
João Lino's avatar
João Lino committed
1406
    default: {}
João Lino's avatar
João Lino committed
1407
  }
João Lino's avatar
João Lino committed
1408
  mdBeerProfileMenu._selection = eBeerProfileMenu_NULL;
1409 1410
}

João Lino's avatar
João Lino committed
1411 1412 1413
void runStageSelection() {
  switch (mdStageMenu._selection) {
    case eStageMenu_Startpoint: {
João Lino's avatar
João Lino committed
1414 1415 1416
        runStageSelection_Generic( &startpointTime, &startpointTemperature );
        break;
      }
João Lino's avatar
João Lino committed
1417
    case eStageMenu_BetaGlucanase: {
João Lino's avatar
João Lino committed
1418 1419 1420
        runStageSelection_Generic( &betaGlucanaseTime, &betaGlucanaseTemperature );
        break;
      }
João Lino's avatar
João Lino committed
1421
    case eStageMenu_Debranching: {
João Lino's avatar
João Lino committed
1422 1423 1424
        runStageSelection_Generic( &debranchingTime, &debranchingTemperature );
        break;
      }
João Lino's avatar
João Lino committed
1425
    case eStageMenu_Proteolytic: {
João Lino's avatar
João Lino committed
1426 1427 1428
        runStageSelection_Generic( &proteolyticTime, &proteolyticTemperature );
        break;
      }
João Lino's avatar
João Lino committed
1429
    case eStageMenu_BetaAmylase: {
João Lino's avatar
João Lino committed
1430 1431 1432
        runStageSelection_Generic( &betaAmylaseTime, &betaAmylaseTemperature );
        break;
      }
João Lino's avatar
João Lino committed
1433
    case eStageMenu_AlphaAmylase: {
João Lino's avatar
João Lino committed
1434 1435 1436
        runStageSelection_Generic( &alphaAmylaseTime, &alphaAmylaseTemperature );
        break;
      }
João Lino's avatar
João Lino committed
1437
    case eStageMenu_Mashout: {
João Lino's avatar
João Lino committed
1438 1439 1440
        runStageSelection_Generic( &mashoutTime, &mashoutTemperature );
        break;
      }
João Lino's avatar
João Lino committed
1441
    case eStageMenu_Recirculation: {
João Lino's avatar
João Lino committed
1442 1443 1444
        runStageSelection_Generic( &recirculationTime, &recirculationTemperature );
        break;
      }
João Lino's avatar
João Lino committed
1445
    case eStageMenu_Sparge: {
João Lino's avatar
João Lino committed
1446 1447 1448
        runStageSelection_Generic( &spargeTime, &spargeTemperature );
        break;
      }
João Lino's avatar
João Lino committed
1449
    case eStageMenu_Boil: {
João Lino's avatar
João Lino committed
1450 1451 1452
        runStageSelection_Generic( &boilTime, &boilTemperature );
        break;
      }
João Lino's avatar
João Lino committed
1453
    case eStageMenu_Cooling: {
João Lino's avatar
João Lino committed
1454 1455 1456
        runStageSelection_Generic( &coolingTime, &coolingTemperature );
        break;
      }
João Lino's avatar
João Lino committed
1457
    case eStageMenu_Back: {
João Lino's avatar
João Lino committed
1458 1459 1460
        resetMenu( true );
        break;
      }
João Lino's avatar
João Lino committed
1461
    default: {}
João Lino's avatar
João Lino committed
1462
  }
João Lino's avatar
João Lino committed
1463 1464
  mdStageMenu._selection = eStageMenu_NULL;
}
1465

João Lino's avatar
João Lino committed
1466 1467 1468
void runSettingsSelection() {
  switch (mdSettingsMenu._selection) {
    case eSettingsMenu_Pump: {
João Lino's avatar
João Lino committed
1469 1470
        //bool bNewPumpStatus = xSetGenericValue( iPumpSpeed ? 0 : 1, PUMP_SPEED_DEFAULT, 0, 1, "pump", "bool" );
        bool bNewPumpStatus = xSetGenericValue( pump.isPumpOn() ? 1 : 0, PUMP_SPEED_DEFAULT, 0, 1, "pump", "bool" );
João Lino's avatar
João Lino committed
1471
        if ( cancel ) {
João Lino's avatar
João Lino committed
1472 1473
          cancel = false;
        }
João Lino's avatar
João Lino committed
1474 1475
        else {
          if ( bNewPumpStatus ) {
João Lino's avatar
João Lino committed
1476 1477
            pump.setTargetPumpSpeed(pump.getMaxSpeed());
            //iPumpSpeed = PUMP_SPEED_MAX_MOSFET;
João Lino's avatar
João Lino committed
1478
          } else {
João Lino's avatar
João Lino committed
1479 1480
            pump.setTargetPumpSpeed(pump.getNullSpeed());
            //iPumpSpeed = PUMP_SPEED_STOP_MOSFET;
João Lino's avatar
João Lino committed
1481
          }
João Lino's avatar
João Lino committed
1482 1483
          //analogWrite(PUMP_PIN, iPumpSpeed);
          pump.process();
João Lino's avatar
João Lino committed
1484
        }
João Lino's avatar
João Lino committed
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
        backToStatus();
        break;
      }
    case eSettingsMenu_PT100_Element: {
        backToStatus();
        break;
      }
    case eSettingsMenu_PT100_Up: {
        backToStatus();
        break;
      }
    case eSettingsMenu_PT100_Down: {
        backToStatus();
        break;
João Lino's avatar
João Lino committed
1499
      }
João Lino's avatar
João Lino committed
1500
    case eSettingsMenu_Back: {
João Lino's avatar
João Lino committed
1501 1502 1503
        resetMenu( true );
        break;
      }
João Lino's avatar
João Lino committed
1504
    default: {}
João Lino's avatar
João Lino committed
1505
  }
João Lino's avatar
João Lino committed
1506
  mdSettingsMenu._selection = eSettingsMenu_NULL;
João Lino's avatar
Rel.3  
João Lino committed
1507 1508
}

João Lino's avatar
João Lino committed
1509 1510 1511 1512 1513
void runMaltSelection() {
  switch (mdMaltMenu._selection) {
    case eMaltMenu_CastleMalting_Chteau_Pilsen_2RS: {
        backToStatus();
        break;
João Lino's avatar
João Lino committed
1514
      }
João Lino's avatar
João Lino committed
1515 1516 1517
    case eMaltMenu_CastleMalting_Wheat_Blanc: {
        backToStatus();
        break;
João Lino's avatar
João Lino committed
1518
      }
João Lino's avatar
João Lino committed
1519
    case eMaltMenu_Back: {
João Lino's avatar
João Lino committed
1520 1521 1522
        resetMenu( true );
        break;
      }
João Lino's avatar
João Lino committed
1523
    default: {}
João Lino's avatar
Rel.3  
João Lino committed
1524
  }
João Lino's avatar
João Lino committed
1525
  mdMaltMenu._selection = eMaltMenu_NULL;
1526 1527
}

João Lino's avatar
João Lino committed
1528 1529 1530
// ************************ MENU HELPERS ******************************
void runMenuProcessor( MenuData *data ) {
  data->_position = rotaryEncoderVirtualPosition;         // Read position
1531

João Lino's avatar
João Lino committed
1532 1533
  data->_repaint = repaint;                               // Request repaint
  repaint = displayGenericMenu( &lcd, data );             // Display menu
João Lino's avatar
Rel.3  
João Lino committed
1534

João Lino's avatar
João Lino committed
1535
  if ( checkForEncoderSwitchPush( true ) ) {              // Read selection
João Lino's avatar
João Lino committed
1536
    if ( cancel ) {
João Lino's avatar
João Lino committed
1537 1538 1539
      resetMenu( true );
      return;
    }
João Lino's avatar
João Lino committed
1540
    data->_selection = data->_position;
1541
  }
João Lino's avatar
João Lino committed
1542

João Lino's avatar
João Lino committed
1543
  (data->_selectionFunction)();                           // Run selection function
1544 1545
}

João Lino's avatar
João Lino committed
1546
void runStageSelection_Generic( unsigned long * selectedStageTime, int *selectedStageTemperature) {
João Lino's avatar
João Lino committed
1547 1548
  unsigned long selectedStageTimeStorage = *selectedStageTime;
  int selectedStageTemperatureStorage = *selectedStageTemperature;
João Lino's avatar
João Lino committed
1549

João Lino's avatar
João Lino committed
1550
  *selectedStageTime = getTimer( *selectedStageTime );
João Lino's avatar
João Lino committed
1551
  if ( cancel ) {
João Lino's avatar
João Lino committed
1552 1553 1554
    *selectedStageTime = selectedStageTimeStorage;
    cancel = false;
  }
João Lino's avatar
João Lino committed
1555 1556
  else {
    *selectedStageTemperature = getTemperature( *selectedStageTemperature );
João Lino's avatar
João Lino committed
1557
    if ( cancel ) {
João Lino's avatar
João Lino committed
1558 1559 1560 1561
      *selectedStageTime = selectedStageTimeStorage;
      *selectedStageTemperature = selectedStageTemperatureStorage;
      cancel = false;
    }
João Lino's avatar
João Lino committed
1562
  }
João Lino's avatar
João Lino committed
1563
  backToStatus();
1564 1565
}

João Lino's avatar
João Lino committed
1566 1567
void xStartStageHeadless( eCookingStages nextStage, bool bPurgePump ) {
  xStartStage( NULL, NULL, nextStage, bPurgePump, false, false, false );
João Lino's avatar
Rel.3  
João Lino committed
1568 1569
}

João Lino's avatar
João Lino committed
1570 1571
void xStartStageInteractive( unsigned long *stageTime, int *stageTemperature, eCookingStages nextStage ) {
  xStartStage( stageTime, stageTemperature, nextStage, true, true, true, true );
1572 1573
}

João Lino's avatar
João Lino committed
1574
void xStartStage( unsigned long *stageTime, int *stageTemperature, eCookingStages nextStage, bool bPurgePump, bool bSetFinalYield, bool bSetTime, bool bSetTemperature ) {
João Lino's avatar
João Lino committed
1575 1576 1577
  int finalYieldStorage = finalYield;
  unsigned long stageTimeStorage = *stageTime;
  int stageTemperatureStorage = *stageTemperature;
João Lino's avatar
João Lino committed
1578

João Lino's avatar
João Lino committed
1579
  if (bSetFinalYield) {
João Lino's avatar
João Lino committed
1580
    finalYield = getFinalYield( finalYield, SETTING_MACHINE_YIELD_DEFAULT );
João Lino's avatar
João Lino committed
1581
    if ( cancel ) {
João Lino's avatar
João Lino committed
1582
      finalYield = finalYieldStorage;
João Lino's avatar
João Lino committed
1583

João Lino's avatar
João Lino committed
1584
      cancel = false;
João Lino's avatar
João Lino committed
1585
      backToStatus();
João Lino's avatar
João Lino committed
1586 1587
      return;
    }
João Lino's avatar
Rel.3  
João Lino committed
1588
  }
João Lino's avatar
João Lino committed
1589
  if (bSetTime) {
João Lino's avatar
João Lino committed
1590
    (*stageTime) = getTimer( clockCounter / 1000, *stageTime );
João Lino's avatar
João Lino committed
1591
    if ( cancel ) {
João Lino's avatar
João Lino committed
1592 1593
      finalYield = finalYieldStorage;
      *stageTime = stageTimeStorage;
João Lino's avatar
João Lino committed
1594

João Lino's avatar
João Lino committed
1595
      cancel = false;
João Lino's avatar
João Lino committed
1596
      backToStatus();
João Lino's avatar
João Lino committed
1597 1598
      return;
    }
João Lino's avatar
Rel.3  
João Lino committed
1599
  }
João Lino's avatar
João Lino committed
1600
  if (bSetTemperature) {
João Lino's avatar
João Lino committed
1601
    (*stageTemperature) = getTemperature( cookTemperature, *stageTemperature );
João Lino's avatar
João Lino committed
1602
    if ( cancel ) {
João Lino's avatar
João Lino committed
1603 1604 1605
      finalYield = finalYieldStorage;
      *stageTime = stageTimeStorage;
      *stageTemperature = stageTemperatureStorage;
João Lino's avatar
João Lino committed
1606

João Lino's avatar
João Lino committed
1607
      cancel = false;
João Lino's avatar
João Lino committed
1608
      backToStatus();
João Lino's avatar
João Lino committed
1609 1610
      return;
    }
João Lino's avatar
Rel.3  
João Lino committed
1611
  }
João Lino's avatar
João Lino committed
1612

João Lino's avatar
João Lino committed
1613
  xSafeHardwarePowerOff();                      // Stop anything that might be still going on
João Lino's avatar
João Lino committed
1614 1615
  if (bPurgePump) {
    xPurgePump();
1616
  }
João Lino's avatar
João Lino committed
1617 1618 1619
  startBrewing();
  xSetupStage( nextStage );
  backToStatus();
1620
}
João Lino's avatar
João Lino committed
1621
// ##################################################### Menus ###################################################################
1622 1623 1624 1625

// #################################################### Helpers ##################################################################

void startBrewing() {
1626 1627
  //sing(MELODY_SUPER_MARIO, PIEZO_PIN);

1628 1629 1630 1631 1632
  cooking = true;
}

void stopBrewing() {
  cooking = false;
1633
  xSafeHardwarePowerOff();
1634 1635
}

João Lino's avatar
João Lino committed
1636 1637 1638
void resetMenu( boolean requestRepaintPaint ) {
  eMenuType = eMenuType_Main;

1639
  if ( requestRepaintPaint ) {
João Lino's avatar
João Lino committed
1640 1641
    repaint = true;
  }
1642

João Lino's avatar
João Lino committed
1643
  xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMainMenu._position, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );       // reset operation state
João Lino's avatar
João Lino committed
1644 1645
}

1646 1647
void backToStatus() {
  lastInterruptTime = millis() - SETTING_MAX_INACTIVITY_TIME - 1;
João Lino's avatar
João Lino committed
1648
  resetMenu(true);
1649 1650 1651 1652
}
// #################################################### Helpers ##################################################################

// #################################################### Set Variables ##################################################################
João Lino's avatar
João Lino committed
1653

João Lino's avatar
João Lino committed
1654 1655 1656 1657 1658 1659
int getTemperature(int initialValue ) {
  return getTemperature( initialValue, initialValue );
}
int getTemperature(int initialValue, int defaultValue ) {
  return xSetGenericValue( initialValue, defaultValue, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, MENU_GLOBAL_STR_TEMPERATURE, MENU_GLOBAL_STR_CELSIUS );
}
João Lino's avatar
João Lino committed
1660

João Lino's avatar
João Lino committed
1661 1662 1663 1664 1665 1666
int getFinalYield( int initialValue ) {
  return getFinalYield( initialValue, SETTING_MACHINE_YIELD_DEFAULT );
}
int getFinalYield( int initialValue, int defaultValue ) {
  return xSetGenericValue( initialValue, defaultValue, SETTING_MACHINE_YIELD_CAPACITY_MIN, SETTING_MACHINE_YIELD_CAPACITY_MAX, "Final Yield", "l" );
}
João Lino's avatar
João Lino committed
1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686

int xSetGenericValue(int initialValue, int defaultValue, int minimumValue, int maximumValue, const char *valueName, const char *unit) {
  xSetupRotaryEncoder( eRotaryEncoderMode_Generic, initialValue, maximumValue, minimumValue, 1, 5 );

  // initialize variables
  int rotaryEncoderPreviousPosition = 0;

  // Setup Screen
  lcd.clear();
  lcd.home();
  lcd.print( "Set " );
  lcd.print( valueName );
  lcd.print( "(" );
  lcd.print( defaultValue );
  lcd.print( ")" );
  lcd.setCursor ( 0 , LCD_VERTICAL_RESOLUTION - 1 );
  lcd.print( "       0 " );
  lcd.print( unit );

  while (true) {
João Lino's avatar
João Lino committed
1687 1688
    if ( checkForEncoderSwitchPush( true ) ) {                  // Check if pushbutton is pressed
      if ( cancel ) return rotaryEncoderVirtualPosition;
João Lino's avatar
João Lino committed
1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722
      break;
    }
    else {
      xManageMachineSystems();                            // Don't forget to keep an eye on the cooking
    }

    // Check if there was an update by the rotary encoder
    if ( rotaryEncoderVirtualPosition != rotaryEncoderPreviousPosition ) {
      rotaryEncoderPreviousPosition = rotaryEncoderVirtualPosition;

      lcd.setCursor( 0, LCD_VERTICAL_RESOLUTION - 1 );
      lcd.print( "     " );
      if ( rotaryEncoderVirtualPosition < 10 ) {
        lcd.print( "  " );
      }
      else {
        if ( rotaryEncoderVirtualPosition < 100 ) {
          lcd.print( " " );
        }
      }
      lcd.print( rotaryEncoderVirtualPosition );
      lcd.print( " " );
      lcd.print( unit );
      lcd.println( "                " );
    }
  }

  return rotaryEncoderVirtualPosition;
}

int getTimer( int initialValue ) {
  return getTimer( initialValue, initialValue );
}

João Lino's avatar
João Lino committed
1723
int getTimer( int initialValue, int defaultValue ) {
João Lino's avatar
João Lino committed
1724
  // set operation state | INPUT : eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep
João Lino's avatar
João Lino committed
1725
  xSetupRotaryEncoder( eRotaryEncoderMode_Time, initialValue, 7200, 0, 1, 30 );
1726 1727

  // initialize variables
service-config's avatar
Mixer  
service-config committed
1728
  int rotaryEncoderPreviousPosition = 0;
1729 1730
  int minutes = 0;
  int seconds = 0;
1731

1732 1733
  // Setup Screen
  lcd.clear();
1734
  lcd.home();
João Lino's avatar
João Lino committed
1735
  lcd.print("Set Time (");
1736
  minutes = defaultValue / 60;
João Lino's avatar
João Lino committed
1737
  lcd.print(minutes);
1738
  seconds = defaultValue - minutes * 60;
João Lino's avatar
João Lino committed
1739
  lcd.print(":");
1740
  if (seconds < 10) {
João Lino's avatar
João Lino committed
1741 1742 1743 1744
    lcd.print("0");
  }
  lcd.print(seconds);
  lcd.print(")");
1745
  lcd.setCursor (0, LCD_VERTICAL_RESOLUTION - 1);
1746
  lcd.print("      0:00");
1747 1748

  while (true) {
João Lino's avatar
João Lino committed
1749 1750
    if ( checkForEncoderSwitchPush( true ) ) {
      if ( cancel ) return rotaryEncoderVirtualPosition;
1751
      break;
João Lino's avatar
João Lino committed
1752 1753 1754
    }
    else {
      xManageMachineSystems();                            // Don't forget to keep an eye on the cooking
João Lino's avatar
João Lino committed
1755
    }
1756

1757
    // display current timer
service-config's avatar
Mixer  
service-config committed
1758 1759
    if (rotaryEncoderVirtualPosition != rotaryEncoderPreviousPosition) {
      rotaryEncoderPreviousPosition = rotaryEncoderVirtualPosition;
1760 1761 1762 1763 1764 1765
      minutes = rotaryEncoderVirtualPosition / 60;
      seconds = rotaryEncoderVirtualPosition - minutes * 60;

      lcd.setCursor (0, LCD_VERTICAL_RESOLUTION - 1);

      if (minutes < 100) {
João Lino's avatar
João Lino committed
1766 1767
        lcd.print(" ");
      }
1768
      if (minutes < 10) {
João Lino's avatar
João Lino committed
1769 1770 1771
        lcd.print(" ");
      }
      lcd.print("    ");
1772 1773
      lcd.print(minutes);
      lcd.print(":");
1774
      if (seconds < 10) {
1775 1776 1777 1778 1779 1780
        lcd.print("0");
      }
      lcd.print(seconds);
      lcd.println("                ");
    }
  }
1781

service-config's avatar
Mixer  
service-config committed
1782
  return rotaryEncoderVirtualPosition;
1783 1784
}

João Lino's avatar
João Lino committed
1785 1786 1787 1788 1789 1790
boolean checkForEncoderSwitchPush( bool cancelable ) {
  boolean gotPush = digitalRead(ROTARY_ENCODER_SW_PIN);
  if (gotPush) {           // Check if pushbutton is pressed
    unsigned long cancleTimer = millis();
    while (digitalRead(ROTARY_ENCODER_SW_PIN)) {        // Wait until switch is released
      delay(ROTARY_ENCODER_SW_DEBOUNCE_TIME);           // debounce
João Lino's avatar
João Lino committed
1791 1792

      if ( ((millis() - cancleTimer) >= SETTING_CANCEL_TIMER ) && cancelable ) {
João Lino's avatar
João Lino committed
1793
        sing(BUZZ_1, PIEZO_PIN);
1794 1795
      }
    }
1796

João Lino's avatar
João Lino committed
1797
    if ( ((millis() - cancleTimer) >= SETTING_CANCEL_TIMER) && cancelable ) {
João Lino's avatar
João Lino committed
1798
      cancel = true;
1799 1800
    }
  }
1801

João Lino's avatar
João Lino committed
1802
  return gotPush;
João Lino's avatar
João Lino committed
1803 1804
}

João Lino's avatar
João Lino committed
1805 1806 1807 1808
unsigned long getInactivityTime() {
  unsigned long now = millis();
  unsigned long rotaryEncoderInactivityTime = now - lastInterruptTime;

1809
  if (rotaryEncoderInactivityTime > SETTING_MAX_INACTIVITY_TIME) {
João Lino's avatar
João Lino committed
1810
    if (checkForEncoderSwitchPush( false )) {
1811 1812 1813 1814 1815 1816
      now = millis();
      rotaryEncoderInactivityTime = now - lastInterruptTime;
      rotarySwDetectTime = now;

      repaint = true;
      refresh = true;
João Lino's avatar
João Lino committed
1817 1818
    }
  }
1819

João Lino's avatar
João Lino committed
1820 1821 1822 1823
  unsigned long switchInactivityTime = now - rotarySwDetectTime;
  return rotaryEncoderInactivityTime > switchInactivityTime ? switchInactivityTime : rotaryEncoderInactivityTime ;
}

1824
// ###################### Set Variables ##################################################
1825

João Lino's avatar
Rel.3  
João Lino committed
1826
void xWaitForAction(String title, String message) {
1827 1828
  unsigned long now = millis();
  unsigned long warningBeepTimeInterval = 0;
1829
  while (true) {
1830 1831
    now = millis();
    
João Lino's avatar
João Lino committed
1832
    if ( checkForEncoderSwitchPush( false ) ) {                  // Check if pushbutton is pressed
João Lino's avatar
Rel.3  
João Lino committed
1833
      break;
João Lino's avatar
João Lino committed
1834 1835
    }
    else {
João Lino's avatar
Rel.3  
João Lino committed
1836
      // Print the message
1837
      if (! lcdPrint(&lcd, title, message)) {
João Lino's avatar
Rel.3  
João Lino committed
1838 1839
        break;
      }
1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935

      unsigned long now = millis();
      if( now - warningBeepTimeInterval > SETTING_WARNING_BEEP_INTERVAL ) {
        warningBeepTimeInterval = now;
        sing(BUZZ_2, PIEZO_PIN);
      }
    }
  }
}

void printBeerProfile( void ) {
  #ifdef INFO
  Serial.println("############# Beer Profile #############");
  Serial.print("#  beerProfile       ");
  Serial.print( mdBeerProfileMenu._dialog[beerProfile+1] );
  Serial.println("  #");
  Serial.println("############ Time per Stage ############");
  Serial.print("#  startpointTime              ");
  printTime(startpointTime           );
  Serial.println("  #");
  Serial.print("#  betaGlucanaseTime           ");
  printTime(betaGlucanaseTime        );
  Serial.println("  #");
  Serial.print("#  debranchingTime             ");
  printTime(debranchingTime          );
  Serial.println("  #");
  Serial.print("#  proteolyticTime             ");
  printTime(proteolyticTime          );
  Serial.println("  #");
  Serial.print("#  betaAmylaseTime             ");
  printTime(betaAmylaseTime          );
  Serial.println("  #");
  Serial.print("#  alphaAmylaseTime            ");
  printTime(alphaAmylaseTime         );
  Serial.println("  #");
  Serial.print("#  mashoutTime                 ");
  printTime(mashoutTime              );
  Serial.println("  #");
  Serial.print("#  recirculationTime           ");
  printTime(recirculationTime        );
  Serial.println("  #");
  Serial.print("#  spargeTime                  ");
  printTime(spargeTime               );
  Serial.println("  #");
  Serial.print("#  boilTime                    ");
  printTime(boilTime                 );
  Serial.println("  #");
  Serial.print("#  coolingTime                 ");
  printTime(coolingTime              );
  Serial.println("  #");
  Serial.println("######## Teperature per Stage ##########");
  Serial.print("#  startpointTemperature       ");
  printTemperature(startpointTemperature    );
  Serial.println("  #");
  Serial.print("#  betaGlucanaseTemperature    ");
  printTemperature(betaGlucanaseTemperature );
  Serial.println("  #");
  Serial.print("#  debranchingTemperature      ");
  printTemperature(debranchingTemperature   );
  Serial.println("  #");
  Serial.print("#  proteolyticTemperature      ");
  printTemperature(proteolyticTemperature   );
  Serial.println("  #");
  Serial.print("#  betaAmylaseTemperature      ");
  printTemperature(betaAmylaseTemperature   );
  Serial.println("  #");
  Serial.print("#  alphaAmylaseTemperature     ");
  printTemperature(alphaAmylaseTemperature  );
  Serial.println("  #");
  Serial.print("#  mashoutTemperature          ");
  printTemperature(mashoutTemperature       );
  Serial.println("  #");
  Serial.print("#  recirculationTemperature    ");
  printTemperature(recirculationTemperature );
  Serial.println("  #");
  Serial.print("#  spargeTemperature           ");
  printTemperature(spargeTemperature        );
  Serial.println("  #");
  Serial.print("#  boilTemperature             ");
  printTemperature(boilTemperature          );
  Serial.println("  #");
  Serial.print("#  coolingTemperature          ");
  printTemperature(coolingTemperature       );
  Serial.println("  #");
  Serial.println("########################################");
  if( beerProfile == eBeerProfile_Trigo) {
    Serial.print("#  finalYield                    ");
    if(finalYield < 10) {
      Serial.print(" ");
    }
    Serial.print(finalYield);
    Serial.println(" l  #");
    float wheatAmount = PROFILE_TRIGO_WHEAT_MULTIPLIER * ((float) finalYield);
    Serial.print("#  wheatAmount               ");
    if(wheatAmount < 10) {
      Serial.print(" ");
1936
    }
1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002
    Serial.print(wheatAmount);
    Serial.println(" Kg  #");
    float pilsnerAmount = PROFILE_TRIGO_PILSNER_MULTIPLIER * ((float) finalYield);
    Serial.print("#  pilsnerAmount             ");
    if(pilsnerAmount < 10) {
      Serial.print(" ");
    }
    Serial.print(pilsnerAmount);
    Serial.println(" Kg  #");
    float strikeWaterAmount = (pilsnerAmount + wheatAmount) * PROFILE_TRIGO_MASH_THICKNESS;
    Serial.print("#  strikeWaterAmount          ");
    if(strikeWaterAmount < 10) {
      Serial.print(" ");
    }
    Serial.print(strikeWaterAmount);
    Serial.println(" l  #");
    float spargeWaterAmount = PROFILE_TRIGO_SPARGE_WATER_MULTIPLIER * ((float) finalYield);
    Serial.print("#  spargeWaterAmount          ");
    if(spargeWaterAmount < 10) {
      Serial.print(" ");
    }
    Serial.print(spargeWaterAmount);
    Serial.println(" l  #");
    float herkulesAmount = PROFILE_TRIGO_HERKULES_MULTIPLIER * ((float) finalYield);
    Serial.print("#  herkulesAmount             ");
    if(herkulesAmount < 10) {
      Serial.print(" ");
    }
    Serial.print(herkulesAmount);
    Serial.println(" g  #");
    float traditionAmount = PROFILE_TRIGO_TRADITION_MULTIPLIER * ((float) finalYield);
    Serial.print("#  traditionAmount            ");
    if(traditionAmount < 10) {
      Serial.print(" ");
    }
    Serial.print(traditionAmount);
    Serial.println(" g  #");
    Serial.println("########################################");
  }
#endif
}

void printTime( unsigned long timeToPrint ) {
  unsigned long minutes = timeToPrint /60;
  unsigned long seconds = timeToPrint %60;

  if (minutes < 100) {
    Serial.print(" ");
  }
  if (minutes < 10) {
    Serial.print(" ");
  }
  Serial.print(minutes);
  Serial.print(":");
  if (seconds < 10) {
    Serial.print("0");
  }
  Serial.print(seconds);
}

void printTemperature( int temparatureToPrint ) {
  if (temparatureToPrint < 100) {
    Serial.print(" ");
  }
  if (temparatureToPrint < 10) {
    Serial.print(" ");
2003
  }
2004 2005 2006 2007
  Serial.print(temparatureToPrint);
  Serial.print(" ");
  Serial.write(176);
  Serial.print("C");
2008
}
2009