brew.ino 69.5 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
Rel.3  
João Lino committed
7
#define DEBUG
8

9
// ######################### LIBRARIES #########################
João Lino's avatar
João Lino committed
10
#include "brew.h"
11

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

eCookingStages          cookingStage;
eBeerProfile            beerProfile;

eMenuType               eMenuType;

21 22 23 24 25 26
MenuData                mdMainMenu =            { ._title = MENU_MAIN_TITLE, ._dialog = MENU_MAIN_DIALOG, ._position = MENU_MAIN_INIT_POSITION, ._selection = MENU_MAIN_INIT_SELECTION, ._repaint = MENU_MAIN_INIT_REPAINT };
MenuData                mdStartFromStageMenu =  { ._title = MENU_START_TITLE, ._dialog = MENU_START_DIALOG, ._position = MENU_START_INIT_POSITION, ._selection = MENU_START_INIT_SELECTION, ._repaint = MENU_START_INIT_REPAINT };
MenuData                mdBeerProfileMenu =     { ._title = MENU_PROFILE_TITLE, ._dialog = MENU_PROFILE_DIALOG, ._position = MENU_PROFILE_INIT_POSITION, ._selection = MENU_PROFILE_INIT_SELECTION, ._repaint = MENU_PROFILE_INIT_REPAINT };
MenuData                mdStageMenu =           { ._title = MENU_STAGE_TITLE, ._dialog = MENU_STAGE_DIALOG, ._position = MENU_STAGE_INIT_POSITION, ._selection = MENU_STAGE_INIT_SELECTION, ._repaint = MENU_STAGE_INIT_REPAINT };
MenuData                mdMaltMenu =            { ._title = MENU_MALT_TITLE, ._dialog = MENU_MALT_DIALOG, ._position = MENU_MALT_INIT_POSITION, ._selection = MENU_MALT_INIT_SELECTION, ._repaint = MENU_MALT_INIT_REPAINT };
MenuData                mdSettingsMenu =        { ._title = MENU_SETTINGS_TITLE, ._dialog = MENU_SETTINGS_DIALOG, ._position = MENU_SETTINGS_INIT_POSITION, ._selection = MENU_SETTINGS_INIT_SELECTION, ._repaint = MENU_SETTINGS_INIT_REPAINT };
João Lino's avatar
João Lino committed
27

28 29
//eMainMenuOptions        eMainMenuPosition;
//eMainMenuOptions        eMainMenuSelection;
João Lino's avatar
João Lino committed
30 31
eStageMenuOptions       eStartFromStageMenuPosition;
eStageMenuOptions       eStartFromStageMenuSelection;
João Lino's avatar
Rel.3  
João Lino committed
32 33 34 35 36
eBeerProfileMenuOptions eBeerProfileMenuPosition;
eBeerProfileMenuOptions eBeerProfileMenuSelection;
eStageMenuOptions       eStageMenuPosition;
eStageMenuOptions       eStageMenuSelection;
eMaltMenuOptions        eMaltMenuPosition;
37
eMaltMenuOptions        eMaltMenuSelection;
João Lino's avatar
Rel.3  
João Lino committed
38 39 40
eSettingsMenuOptions    eSettingsMenuPosition;
eSettingsMenuOptions    eSettingsMenuSelection;

41
// ++++++++++++++++++++++++ Global Variables ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
42 43
boolean                 cooking;

João Lino's avatar
Rel.3  
João Lino committed
44 45 46 47
unsigned long           clockStartTime;
unsigned long           clockLastUpdate;
long                    clockCounter;
unsigned long           clockIgnore;
João Lino's avatar
João Lino committed
48 49 50
boolean                 clockStart;
boolean                 clockEnd;

João Lino's avatar
Rel.3  
João Lino committed
51
unsigned long           cookTime;
João Lino's avatar
João Lino committed
52 53 54
int                     cookTemperature;
//cook_mode_list        cookMode;
//int                   cookMixerSpeed;
João Lino's avatar
Rel.3  
João Lino committed
55
int                     finalYield;
56

João Lino's avatar
Rel.3  
João Lino committed
57 58 59 60 61 62 63 64 65 66 67 68
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;
69

João Lino's avatar
João Lino committed
70 71 72 73 74 75 76 77 78 79 80
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
81
int                     cleaningTemperature;
João Lino's avatar
João Lino committed
82 83 84

boolean                 refresh;
boolean                 repaint;
85

João Lino's avatar
Rel.3  
João Lino committed
86 87
boolean                 bStatusElement;

88
// ++++++++++++++++++++++++ Interrupts ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
89
static unsigned long    lastInterruptTime;
90

91
// ++++++++++++++++++++++++ Rotary Encoder ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
92 93 94 95 96
volatile int            rotaryEncoderVirtualPosition = 0;
volatile int            rotaryEncoderMaxPosition = 1;
volatile int            rotaryEncoderMinPosition = 0;
volatile int            rotaryEncoderSingleStep = 1;
volatile int            rotaryEncoderMultiStep = 1;
97

João Lino's avatar
João Lino committed
98 99
volatile boolean        onISR = false;

João Lino's avatar
João Lino committed
100 101
unsigned long           rotarySwDetectTime;

102
// ++++++++++++++++++++++++ Heating Element Relay ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
103 104 105
int                     iWindowSize;             // Time frame to operate in
unsigned long           windowStartTime;
double                  dWattPerPulse;
106

107 108 109
// ++++++++++++++++++++++++ Pump ++++++++++++++++++++++++
int                     iPumpSpeed;             // Time frame to operate in

110
// ######################### INITIALIZE #########################
111
// ++++++++++++++++++++++++ Library - LiquidCrystal_I2C ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
112
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);
113

João Lino's avatar
João Lino committed
114
// +++++++++++++++++++++++ Temperature +++++++++++++++++++++++
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
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);
130 131

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

136
  // 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
137
  if (diff > ROTARY_ENCODER_DEBOUNCE_TIME) {
João Lino's avatar
João Lino committed
138
    lastInterruptTime = interruptTime;
139 140

    switch (rotaryEncoderMode) {
141 142
      // Input of rotary encoder controling menus
      case eRotaryEncoderMode_Menu: {
143
          if (!digitalRead(ROTARY_ENCODER_DT_PIN)) {
144
            rotaryEncoderVirtualPosition = (rotaryEncoderVirtualPosition + rotaryEncoderSingleStep);
145 146
          }
          else {
147
            rotaryEncoderVirtualPosition = rotaryEncoderVirtualPosition - rotaryEncoderSingleStep;
148 149
          }
          if (rotaryEncoderVirtualPosition > rotaryEncoderMaxPosition) {
150
            rotaryEncoderVirtualPosition = rotaryEncoderMinPosition;
151 152
          }
          if (rotaryEncoderVirtualPosition < rotaryEncoderMinPosition) {
153
            rotaryEncoderVirtualPosition = rotaryEncoderMaxPosition;
154 155 156
          }

          break;
157
        }
158

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

          break;
190
        }
191

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

          break;
service-config's avatar
Mixer  
service-config committed
208
        }
209
      default: {
210 211

        }
212
    }
213

João Lino's avatar
João Lino committed
214 215
    repaint = true;
    refresh = true;
216 217 218
  }
}

219
void xSetupRotaryEncoder( eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep ) {
220 221 222 223 224 225
  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;
226 227
}

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

  // 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
João Lino's avatar
João Lino committed
236
  digitalWrite(HEATING_ELEMENT_OUTPUT_PIN, LOW);  // Turn heading element OFF for safety
João Lino's avatar
Rel.3  
João Lino committed
237 238
  bStatusElement = false;

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

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

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

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

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

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

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

  // ++++++++++++++++++++++++ Heating Element Relay ++++++++++++++++++++++++
  pinMode                         (HEATING_ELEMENT_OUTPUT_PIN, OUTPUT);
  digitalWrite                    (HEATING_ELEMENT_OUTPUT_PIN, LOW);
João Lino's avatar
Rel.3  
João Lino committed
270
  bStatusElement              =   false;
João Lino's avatar
João Lino committed
271 272 273 274 275
  windowStartTime             =   millis();
  dWattPerPulse               =   HEATING_ELEMENT_MAX_WATTAGE / HEATING_ELEMENT_AC_FREQUENCY_HZ;

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

276 277
  // ++++++++++++++++++++++++ Pump ++++++++++++++++++++++++
  pinMode(PUMP_PIN, OUTPUT);   // sets the pin as output
João Lino's avatar
João Lino committed
278
  iPumpSpeed                  =   PUMP_SPEED_STOP_MOSFET;             // Time frame to operate in
279 280
  analogWrite(PUMP_PIN, iPumpSpeed);  // analogWrite values from 0 to 255

João Lino's avatar
João Lino committed
281
  // ++++++++++++++++++++++++ Piezo ++++++++++++++++++++++++
282 283
  pinMode(PIEZO_PIN, OUTPUT);

João Lino's avatar
João Lino committed
284
  // ++++++++++++++++++++++++ Temperature Sensor PT100 ++++++++++++++++++++++++
João Lino's avatar
João Lino committed
285

João Lino's avatar
João Lino committed
286 287 288 289 290
  // ++++++++++++++++++++++++ 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 ++++++++++++++++++++++++
291 292
  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
293 294 295 296 297 298
  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
299
  rotarySwDetectTime = 0;
João Lino's avatar
João Lino committed
300 301

  // ++++++++++++++++++++++++ State Machine ++++++++++++++++++++++++
João Lino's avatar
Rel.3  
João Lino committed
302
  eMenuType                   =   eMenuType_Main;
João Lino's avatar
João Lino committed
303

304 305
  //eMainMenuPosition           =   MENU_MAIN_INIT_POSITION;
  //eMainMenuSelection          =   MENU_MAIN_INIT_SELECTION;
João Lino's avatar
Rel.3  
João Lino committed
306 307 308 309 310 311 312 313 314
  eBeerProfileMenuPosition    =   eBeerProfileMenu_Basic;
  eBeerProfileMenuSelection   =   eBeerProfileMenu_NULL;
  eStageMenuPosition          =   eStageMenu_Startpoint;
  eStageMenuSelection         =   eStageMenu_NULL;
  eMaltMenuPosition           =   eMaltMenu_CastleMalting_Chteau_Pilsen_2RS;
  eMaltMenuSelection          =   eMaltMenu_NULL;
  eSettingsMenuPosition       =   eSettingsMenu_PT100_Element;
  eSettingsMenuSelection      =   eSettingsMenu_NULL;

João Lino's avatar
João Lino committed
315
  cookingStage                =   eCookingStage_Startpoint;
João Lino's avatar
Rel.3  
João Lino committed
316
  beerProfile                 =   eBeerProfile_Basic;
João Lino's avatar
João Lino committed
317
  // ++++++++++++++++++++++++ Global Variables ++++++++++++++++++++++++
João Lino's avatar
Rel.3  
João Lino committed
318

João Lino's avatar
João Lino committed
319
  cooking                     =   false;
320

João Lino's avatar
João Lino committed
321
  clockStartTime              =   0;
João Lino's avatar
Rel.3  
João Lino committed
322
  clockLastUpdate             =   0;
João Lino's avatar
João Lino committed
323 324 325 326
  clockCounter                =   0;
  clockIgnore                 =   0;
  clockStart                  =   false;
  clockEnd                    =   false;
327

João Lino's avatar
João Lino committed
328 329 330 331
  cookTime                    =   3600;
  cookTemperature             =   25;
  //cookMode                  =   quick_start;
  //cookMixerSpeed            =   120;
João Lino's avatar
Rel.3  
João Lino committed
332
  finalYield                  =   25;
João Lino's avatar
João Lino committed
333

João Lino's avatar
João Lino committed
334 335 336 337 338 339 340 341 342 343 344
  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;
João Lino's avatar
Rel.3  
João Lino committed
345
  cleaningTime                =   SETTING_CLEANING_TIME;
João Lino's avatar
João Lino committed
346

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

  refresh                     =   true;
  repaint                     =   true;

  // ++++++++++++++++++++++++ Interrupts ++++++++++++++++++++++++
  lastInterruptTime           =   0;

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

João Lino's avatar
Rel.3  
João Lino committed
369
  // ######################### Code - Run Once #########################
João Lino's avatar
João Lino committed
370
  xSafeHardwarePowerOff           ();
João Lino's avatar
Rel.3  
João Lino committed
371
  xWelcomeUser                    ();
372

João Lino's avatar
Rel.3  
João Lino committed
373
  xSetupRotaryEncoder             ( eRotaryEncoderMode_Menu, eMainMenu_GO, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );
374
}
375

376
// ######################### MAIN LOOP #########################
377 378

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

381 382
  if ( inactivityTime > SETTING_MAX_INACTIVITY_TIME ) {   // Inactivity check
    if (refresh) {
383 384 385
      repaint = true;
      refresh = false;
    }
João Lino's avatar
Rel.3  
João Lino committed
386
    repaint = displayStatus( &lcd, cooking, cookTemperature, basePT100.getCurrentTemperature(), upPT100.getCurrentTemperature(), downPT100.getCurrentTemperature(), clockCounter, repaint );
387 388
  }
  else {
João Lino's avatar
Rel.3  
João Lino committed
389
    runMenu();
390
  }
391

João Lino's avatar
Rel.3  
João Lino committed
392
  xManageMachineSystems();
393 394
}

395 396
// ######################### FUNCTIONS ########################

João Lino's avatar
Rel.3  
João Lino committed
397
void runMenu() {
398
#ifdef DEBUG_OFF
João Lino's avatar
Rel.3  
João Lino committed
399
  boolean debug_go = repaint;
400
  if (debug_go) {
João Lino's avatar
Rel.3  
João Lino committed
401 402 403 404
    debugPrintFunction("runMenu");
    debugPrintVar("repaint", repaint);
    debugPrintVar("eMenuType", eMenuType);
    debugPrintVar("rotaryEncoderVirtualPosition", rotaryEncoderVirtualPosition);
João Lino's avatar
João Lino committed
405
  }
406
#endif
407

408
  switch (eMenuType) {
João Lino's avatar
Rel.3  
João Lino committed
409
    case eMenuType_Main: {
410 411
        //eMainMenuPosition = static_cast<eMainMenuOptions>(rotaryEncoderVirtualPosition);
        mdMainMenu._position = rotaryEncoderVirtualPosition;
412

413 414 415
        mdMainMenu._repaint = repaint;
        repaint = displayGenericMenu( &lcd, &mdMainMenu );
        //repaint = displayMainMenu( &lcd, eMainMenuPosition, repaint );
416

417 418 419 420
        if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) {
          mdMainMenu._selection = mdMainMenu._position;
          //eMainMenuSelection = eMainMenuPosition;
        }
421

422
        runMainMenuSelection();
João Lino's avatar
João Lino committed
423

424 425
        break;
      }
João Lino's avatar
João Lino committed
426
    case eMenuType_StartFromStage: {
427
        eStartFromStageMenuPosition = static_cast<eStageMenuOptions>(rotaryEncoderVirtualPosition);
João Lino's avatar
João Lino committed
428

429
        repaint = displayStageMenu( &lcd, eStartFromStageMenuPosition, repaint );
João Lino's avatar
João Lino committed
430

431 432 433 434 435
        if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) {
          eStartFromStageMenuSelection = eStartFromStageMenuPosition;
        }

        runStartFromStageSelection();
João Lino's avatar
João Lino committed
436

437
        break;
João Lino's avatar
Rel.3  
João Lino committed
438
      }
439 440
    case eMenuType_BeerProfile: {
        eBeerProfileMenuPosition = static_cast<eBeerProfileMenuOptions>(rotaryEncoderVirtualPosition);
João Lino's avatar
João Lino committed
441

442 443 444 445 446
        repaint = displayBeerProfileMenu( &lcd, eBeerProfileMenuPosition, repaint );

        if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) {
          eBeerProfileMenuSelection = eBeerProfileMenuPosition;
        }
João Lino's avatar
João Lino committed
447

448 449 450
        runBeerProfileSelection();

        break;
João Lino's avatar
Rel.3  
João Lino committed
451
      }
452 453
    case eMenuType_Stage: {
        eStageMenuPosition = static_cast<eStageMenuOptions>(rotaryEncoderVirtualPosition);
454

455 456 457 458 459
        repaint = displayStageMenu( &lcd, eStageMenuPosition, repaint );

        if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) {
          eStageMenuSelection = eStageMenuPosition;
        }
460

461 462 463
        runStageSelection();

        break;
João Lino's avatar
Rel.3  
João Lino committed
464
      }
465 466
    case eMenuType_Malt: {
        eMaltMenuPosition = static_cast<eMaltMenuOptions>(rotaryEncoderVirtualPosition);
467

468
        repaint = displayMaltMenu( &lcd, eMaltMenuPosition, repaint );
469

470 471 472 473 474 475 476
        if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) {
          eMaltMenuSelection = eMaltMenuPosition;
        }

        runMaltSelection();

        break;
João Lino's avatar
Rel.3  
João Lino committed
477
      }
478 479
    case eMenuType_Settings: {
        eSettingsMenuPosition = static_cast<eSettingsMenuOptions>(rotaryEncoderVirtualPosition);
480

481 482 483 484 485 486 487 488 489 490
        repaint = displaySettingsMenu( &lcd, eSettingsMenuPosition, repaint );

        if ( gotButtonPress( ROTARY_ENCODER_SW_PIN ) ) {
          eSettingsMenuSelection = eSettingsMenuPosition;
        }

        runSettingsSelection();

        break;
      }
491
  }
João Lino's avatar
Rel.3  
João Lino committed
492

493 494
#ifdef DEBUG_OFF
  if (debug_go) {
João Lino's avatar
Rel.3  
João Lino committed
495
    debugPrintVar("repaint", repaint);
496
  }
497
#endif
498 499
}

João Lino's avatar
Rel.3  
João Lino committed
500
void runSettingsSelection() {
501
  switch (eSettingsMenuSelection) {
João Lino's avatar
João Lino committed
502
    case eSettingsMenu_Pump: {
503 504 505 506 507 508 509
        // Stuff
        if ( xSetGenericValue( iPumpSpeed ? 0 : 1, 0, 1, "pump", "bool" ) ) {
          iPumpSpeed = PUMP_SPEED_MAX_MOSFET;
        } else {
          iPumpSpeed = PUMP_SPEED_STOP_MOSFET;
        }
        analogWrite(PUMP_PIN, iPumpSpeed);
João Lino's avatar
Rel.3  
João Lino committed
510

511 512 513 514
        backToStatus();

        break;
      }
João Lino's avatar
João Lino committed
515
    case eSettingsMenu_PT100_Element: {
516
        // Stuff
João Lino's avatar
João Lino committed
517

518 519 520 521
        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
522
    case eSettingsMenu_PT100_Up: {
523
        // Stuff
João Lino's avatar
Rel.3  
João Lino committed
524

525 526 527 528
        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
529
    case eSettingsMenu_PT100_Down: {
530
        // Stuff
João Lino's avatar
Rel.3  
João Lino committed
531

532 533 534 535
        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
536
    case eSettingsMenu_Back: {
537 538
        eMenuType = eMenuType_Main;
        repaint = true;
João Lino's avatar
Rel.3  
João Lino committed
539

540 541 542 543 544 545
        // reset operation state | INPUT : eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep
        //xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenuPosition, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMainMenu._position, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
546
    default: {
547
      }
João Lino's avatar
Rel.3  
João Lino committed
548 549 550 551 552 553
  }

  eSettingsMenuSelection = eSettingsMenu_NULL;
}

void runMaltSelection() {
554
  switch (eMaltMenuSelection) {
João Lino's avatar
Rel.3  
João Lino committed
555
    case eMaltMenu_CastleMalting_Chteau_Pilsen_2RS: {
556
        // Stuff
João Lino's avatar
Rel.3  
João Lino committed
557

558 559 560 561
        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
562
    case eMaltMenu_CastleMalting_Wheat_Blanc: {
563
        // Stuff
João Lino's avatar
Rel.3  
João Lino committed
564

565 566 567 568
        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
569
    case eMaltMenu_Back: {
570 571
        eMenuType = eMenuType_Main;
        repaint = true;
João Lino's avatar
Rel.3  
João Lino committed
572

573 574 575 576 577 578
        // reset operation state | INPUT : eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep
        //xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenuPosition, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMainMenu._position, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
579
    default: {
580
      }
João Lino's avatar
Rel.3  
João Lino committed
581 582 583 584 585 586
  }

  eMaltMenuSelection = eMaltMenu_NULL;
}

void runStageSelection() {
587
  switch (eStageMenuSelection) {
João Lino's avatar
Rel.3  
João Lino committed
588
    case eStageMenu_Startpoint: {
589
        startpointTime = getTimer( startpointTime );
João Lino's avatar
Rel.3  
João Lino committed
590

591 592 593 594 595 596
        startpointTemperature = xSetGenericValue( startpointTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" );

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
597
    case eStageMenu_BetaGlucanase: {
598
        betaGlucanaseTime = getTimer( betaGlucanaseTime );
João Lino's avatar
Rel.3  
João Lino committed
599

600 601 602 603 604 605
        betaGlucanaseTemperature = xSetGenericValue( betaGlucanaseTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" );

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
606
    case eStageMenu_Debranching: {
607
        debranchingTime = getTimer( debranchingTime );
João Lino's avatar
Rel.3  
João Lino committed
608

609 610 611 612 613 614
        debranchingTemperature = xSetGenericValue( debranchingTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" );

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
615
    case eStageMenu_Proteolytic: {
616
        proteolyticTime = getTimer( proteolyticTime );
João Lino's avatar
Rel.3  
João Lino committed
617

618 619 620 621 622 623
        proteolyticTemperature = xSetGenericValue( proteolyticTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" );

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
624
    case eStageMenu_BetaAmylase: {
625
        betaAmylaseTime = getTimer( betaAmylaseTime );
João Lino's avatar
Rel.3  
João Lino committed
626

627 628 629 630 631 632
        betaAmylaseTemperature = xSetGenericValue( betaAmylaseTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" );

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
633
    case eStageMenu_AlphaAmylase: {
634
        alphaAmylaseTime = getTimer( alphaAmylaseTime );
João Lino's avatar
Rel.3  
João Lino committed
635

636 637 638 639 640 641
        alphaAmylaseTemperature = xSetGenericValue( alphaAmylaseTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" );

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
642
    case eStageMenu_Mashout: {
643
        mashoutTime = getTimer( mashoutTime );
João Lino's avatar
Rel.3  
João Lino committed
644

645 646 647 648 649 650
        mashoutTemperature = xSetGenericValue( mashoutTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" );

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
651
    case eStageMenu_Recirculation: {
652
        recirculationTime = getTimer( recirculationTime );
João Lino's avatar
Rel.3  
João Lino committed
653

654 655 656 657 658 659
        recirculationTemperature = xSetGenericValue( recirculationTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" );

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
660
    case eStageMenu_Sparge: {
661
        spargeTime = getTimer( spargeTime );
João Lino's avatar
Rel.3  
João Lino committed
662

663 664 665 666 667 668
        spargeTemperature = xSetGenericValue( spargeTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" );

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
669
    case eStageMenu_Boil: {
670
        boilTime = getTimer( boilTime );
João Lino's avatar
Rel.3  
João Lino committed
671

672 673 674 675 676 677
        boilTemperature = xSetGenericValue( boilTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" );

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
678
    case eStageMenu_Cooling: {
679
        coolingTime = getTimer( coolingTime );
João Lino's avatar
Rel.3  
João Lino committed
680

681 682 683 684 685 686
        coolingTemperature = xSetGenericValue( coolingTemperature, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" );

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
687
    case eStageMenu_Back: {
688 689
        eMenuType = eMenuType_Main;
        repaint = true;
João Lino's avatar
Rel.3  
João Lino committed
690

691 692 693 694 695 696
        // reset operation state | INPUT : eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep
        //xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenuPosition, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMainMenu._position, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
697
    default: {
698
      }
João Lino's avatar
Rel.3  
João Lino committed
699 700 701 702 703 704
  }

  eStageMenuSelection = eStageMenu_NULL;
}

void runBeerProfileSelection() {
705
  switch (eBeerProfileMenuSelection) {
João Lino's avatar
Rel.3  
João Lino committed
706
    case eBeerProfileMenu_Basic: {
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
        beerProfile                 =   eBeerProfile_Basic;

        startpointTime              =   PROFILE_BASIC_STARTPOINT_TIME;
        betaGlucanaseTime           =   PROFILE_BASIC_BETAGLUCANASE_TIME;
        debranchingTime             =   PROFILE_BASIC_DEBRANCHING_TIME;
        proteolyticTime             =   PROFILE_BASIC_PROTEOLYTIC_TIME;
        betaAmylaseTime             =   PROFILE_BASIC_BETAAMYLASE_TIME;
        alphaAmylaseTime            =   PROFILE_BASIC_ALPHAAMYLASE_TIME;
        mashoutTime                 =   PROFILE_BASIC_MASHOUT_TIME;
        recirculationTime           =   PROFILE_BASIC_RECIRCULATION_TIME;
        spargeTime                  =   PROFILE_BASIC_SPARGE_TIME;
        boilTime                    =   PROFILE_BASIC_BOIL_TIME;
        coolingTime                 =   PROFILE_BASIC_COOLING_TIME;

        startpointTemperature       =   PROFILE_BASIC_STARTPOINT_TEMPERATURE;
        betaGlucanaseTemperature    =   PROFILE_BASIC_BETAGLUCANASE_TEMPERATURE;
        debranchingTemperature      =   PROFILE_BASIC_DEBRANCHING_TEMPERATURE;
        proteolyticTemperature      =   PROFILE_BASIC_PROTEOLYTIC_TEMPERATURE;
        betaAmylaseTemperature      =   PROFILE_BASIC_BETAAMYLASE_TEMPERATURE;
        alphaAmylaseTemperature     =   PROFILE_BASIC_ALPHAAMYLASE_TEMPERATURE;
        mashoutTemperature          =   PROFILE_BASIC_MASHOUT_TEMPERATURE;
        recirculationTemperature    =   PROFILE_BASIC_RECIRCULATION_TEMPERATURE;
        spargeTemperature           =   PROFILE_BASIC_SPARGE_TEMPERATURE;
        boilTemperature             =   PROFILE_BASIC_BOIL_TEMPERATURE;
        coolingTemperature          =   PROFILE_BASIC_COOLING_TEMPERATURE;

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
737
    case eBeerProfileMenu_Trigo: {
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
        beerProfile                 =   eBeerProfile_Trigo;

        startpointTime              =   PROFILE_TRIGO_STARTPOINT_TIME;
        betaGlucanaseTime           =   PROFILE_TRIGO_BETAGLUCANASE_TIME;
        debranchingTime             =   PROFILE_TRIGO_DEBRANCHING_TIME;
        proteolyticTime             =   PROFILE_TRIGO_PROTEOLYTIC_TIME;
        betaAmylaseTime             =   PROFILE_TRIGO_BETAAMYLASE_TIME;
        alphaAmylaseTime            =   PROFILE_TRIGO_ALPHAAMYLASE_TIME;
        mashoutTime                 =   PROFILE_TRIGO_MASHOUT_TIME;
        recirculationTime           =   PROFILE_TRIGO_RECIRCULATION_TIME;
        spargeTime                  =   PROFILE_TRIGO_SPARGE_TIME;
        boilTime                    =   PROFILE_TRIGO_BOIL_TIME;
        coolingTime                 =   PROFILE_TRIGO_COOLING_TIME;

        startpointTemperature       =   PROFILE_TRIGO_STARTPOINT_TEMPERATURE;
        betaGlucanaseTemperature    =   PROFILE_TRIGO_BETAGLUCANASE_TEMPERATURE;
        debranchingTemperature      =   PROFILE_TRIGO_DEBRANCHING_TEMPERATURE;
        proteolyticTemperature      =   PROFILE_TRIGO_PROTEOLYTIC_TEMPERATURE;
        betaAmylaseTemperature      =   PROFILE_TRIGO_BETAAMYLASE_TEMPERATURE;
        alphaAmylaseTemperature     =   PROFILE_TRIGO_ALPHAAMYLASE_TEMPERATURE;
        mashoutTemperature          =   PROFILE_TRIGO_MASHOUT_TEMPERATURE;
        recirculationTemperature    =   PROFILE_TRIGO_RECIRCULATION_TEMPERATURE;
        spargeTemperature           =   PROFILE_TRIGO_SPARGE_TEMPERATURE;
        boilTemperature             =   PROFILE_TRIGO_BOIL_TEMPERATURE;
        coolingTemperature          =   PROFILE_TRIGO_COOLING_TEMPERATURE;

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
768
    case eBeerProfileMenu_IPA: {
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
        beerProfile                 =   eBeerProfile_IPA;

        startpointTime              =   PROFILE_IPA_STARTPOINT_TIME;
        betaGlucanaseTime           =   PROFILE_IPA_BETAGLUCANASE_TIME;
        debranchingTime             =   PROFILE_IPA_DEBRANCHING_TIME;
        proteolyticTime             =   PROFILE_IPA_PROTEOLYTIC_TIME;
        betaAmylaseTime             =   PROFILE_IPA_BETAAMYLASE_TIME;
        alphaAmylaseTime            =   PROFILE_IPA_ALPHAAMYLASE_TIME;
        mashoutTime                 =   PROFILE_IPA_MASHOUT_TIME;
        recirculationTime           =   PROFILE_IPA_RECIRCULATION_TIME;
        spargeTime                  =   PROFILE_IPA_SPARGE_TIME;
        boilTime                    =   PROFILE_IPA_BOIL_TIME;
        coolingTime                 =   PROFILE_IPA_COOLING_TIME;

        startpointTemperature       =   PROFILE_IPA_STARTPOINT_TEMPERATURE;
        betaGlucanaseTemperature    =   PROFILE_IPA_BETAGLUCANASE_TEMPERATURE;
        debranchingTemperature      =   PROFILE_IPA_DEBRANCHING_TEMPERATURE;
        proteolyticTemperature      =   PROFILE_IPA_PROTEOLYTIC_TEMPERATURE;
        betaAmylaseTemperature      =   PROFILE_IPA_BETAAMYLASE_TEMPERATURE;
        alphaAmylaseTemperature     =   PROFILE_IPA_ALPHAAMYLASE_TEMPERATURE;
        mashoutTemperature          =   PROFILE_IPA_MASHOUT_TEMPERATURE;
        recirculationTemperature    =   PROFILE_IPA_RECIRCULATION_TEMPERATURE;
        spargeTemperature           =   PROFILE_IPA_SPARGE_TEMPERATURE;
        boilTemperature             =   PROFILE_IPA_BOIL_TEMPERATURE;
        coolingTemperature          =   PROFILE_IPA_COOLING_TEMPERATURE;

        backToStatus();
João Lino's avatar
Rel.3  
João Lino committed
796

797 798
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
799
    case eBeerProfileMenu_Belga: {
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
        beerProfile                 =   eBeerProfile_Belga;

        startpointTime              =   PROFILE_BELGA_STARTPOINT_TIME;
        betaGlucanaseTime           =   PROFILE_BELGA_BETAGLUCANASE_TIME;
        debranchingTime             =   PROFILE_BELGA_DEBRANCHING_TIME;
        proteolyticTime             =   PROFILE_BELGA_PROTEOLYTIC_TIME;
        betaAmylaseTime             =   PROFILE_BELGA_BETAAMYLASE_TIME;
        alphaAmylaseTime            =   PROFILE_BELGA_ALPHAAMYLASE_TIME;
        mashoutTime                 =   PROFILE_BELGA_MASHOUT_TIME;
        recirculationTime           =   PROFILE_BELGA_RECIRCULATION_TIME;
        spargeTime                  =   PROFILE_BELGA_SPARGE_TIME;
        boilTime                    =   PROFILE_BELGA_BOIL_TIME;
        coolingTime                 =   PROFILE_BELGA_COOLING_TIME;

        startpointTemperature       =   PROFILE_BELGA_STARTPOINT_TEMPERATURE;
        betaGlucanaseTemperature    =   PROFILE_BELGA_BETAGLUCANASE_TEMPERATURE;
        debranchingTemperature      =   PROFILE_BELGA_DEBRANCHING_TEMPERATURE;
        proteolyticTemperature      =   PROFILE_BELGA_PROTEOLYTIC_TEMPERATURE;
        betaAmylaseTemperature      =   PROFILE_BELGA_BETAAMYLASE_TEMPERATURE;
        alphaAmylaseTemperature     =   PROFILE_BELGA_ALPHAAMYLASE_TEMPERATURE;
        mashoutTemperature          =   PROFILE_BELGA_MASHOUT_TEMPERATURE;
        recirculationTemperature    =   PROFILE_BELGA_RECIRCULATION_TEMPERATURE;
        spargeTemperature           =   PROFILE_BELGA_SPARGE_TEMPERATURE;
        boilTemperature             =   PROFILE_BELGA_BOIL_TEMPERATURE;
        coolingTemperature          =   PROFILE_BELGA_COOLING_TEMPERATURE;

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
830
    case eBeerProfileMenu_Red: {
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
        beerProfile                 =   eBeerProfile_Red;

        startpointTime              =   PROFILE_RED_STARTPOINT_TIME;
        betaGlucanaseTime           =   PROFILE_RED_BETAGLUCANASE_TIME;
        debranchingTime             =   PROFILE_RED_DEBRANCHING_TIME;
        proteolyticTime             =   PROFILE_RED_PROTEOLYTIC_TIME;
        betaAmylaseTime             =   PROFILE_RED_BETAAMYLASE_TIME;
        alphaAmylaseTime            =   PROFILE_RED_ALPHAAMYLASE_TIME;
        mashoutTime                 =   PROFILE_RED_MASHOUT_TIME;
        recirculationTime           =   PROFILE_RED_RECIRCULATION_TIME;
        spargeTime                  =   PROFILE_RED_SPARGE_TIME;
        boilTime                    =   PROFILE_RED_BOIL_TIME;
        coolingTime                 =   PROFILE_RED_COOLING_TIME;

        startpointTemperature       =   PROFILE_RED_STARTPOINT_TEMPERATURE;
        betaGlucanaseTemperature    =   PROFILE_RED_BETAGLUCANASE_TEMPERATURE;
        debranchingTemperature      =   PROFILE_RED_DEBRANCHING_TEMPERATURE;
        proteolyticTemperature      =   PROFILE_RED_PROTEOLYTIC_TEMPERATURE;
        betaAmylaseTemperature      =   PROFILE_RED_BETAAMYLASE_TEMPERATURE;
        alphaAmylaseTemperature     =   PROFILE_RED_ALPHAAMYLASE_TEMPERATURE;
        mashoutTemperature          =   PROFILE_RED_MASHOUT_TEMPERATURE;
        recirculationTemperature    =   PROFILE_RED_RECIRCULATION_TEMPERATURE;
        spargeTemperature           =   PROFILE_RED_SPARGE_TEMPERATURE;
        boilTemperature             =   PROFILE_RED_BOIL_TEMPERATURE;
        coolingTemperature          =   PROFILE_RED_COOLING_TEMPERATURE;

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
861
    case eBeerProfileMenu_APA: {
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
        beerProfile                 =   eBeerProfile_APA;

        startpointTime              =   PROFILE_APA_STARTPOINT_TIME;
        betaGlucanaseTime           =   PROFILE_APA_BETAGLUCANASE_TIME;
        debranchingTime             =   PROFILE_APA_DEBRANCHING_TIME;
        proteolyticTime             =   PROFILE_APA_PROTEOLYTIC_TIME;
        betaAmylaseTime             =   PROFILE_APA_BETAAMYLASE_TIME;
        alphaAmylaseTime            =   PROFILE_APA_ALPHAAMYLASE_TIME;
        mashoutTime                 =   PROFILE_APA_MASHOUT_TIME;
        recirculationTime           =   PROFILE_APA_RECIRCULATION_TIME;
        spargeTime                  =   PROFILE_APA_SPARGE_TIME;
        boilTime                    =   PROFILE_APA_BOIL_TIME;
        coolingTime                 =   PROFILE_APA_COOLING_TIME;

        startpointTemperature       =   PROFILE_APA_STARTPOINT_TEMPERATURE;
        betaGlucanaseTemperature    =   PROFILE_APA_BETAGLUCANASE_TEMPERATURE;
        debranchingTemperature      =   PROFILE_APA_DEBRANCHING_TEMPERATURE;
        proteolyticTemperature      =   PROFILE_APA_PROTEOLYTIC_TEMPERATURE;
        betaAmylaseTemperature      =   PROFILE_APA_BETAAMYLASE_TEMPERATURE;
        alphaAmylaseTemperature     =   PROFILE_APA_ALPHAAMYLASE_TEMPERATURE;
        mashoutTemperature          =   PROFILE_APA_MASHOUT_TEMPERATURE;
        recirculationTemperature    =   PROFILE_APA_RECIRCULATION_TEMPERATURE;
        spargeTemperature           =   PROFILE_APA_SPARGE_TEMPERATURE;
        boilTemperature             =   PROFILE_APA_BOIL_TEMPERATURE;
        coolingTemperature          =   PROFILE_APA_COOLING_TEMPERATURE;

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
892
    case eBeerProfileMenu_Custom: {
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922
        beerProfile                 =   eBeerProfile_Custom;

        startpointTime              =   PROFILE_CUSTOM_STARTPOINT_TIME;
        betaGlucanaseTime           =   PROFILE_CUSTOM_BETAGLUCANASE_TIME;
        debranchingTime             =   PROFILE_CUSTOM_DEBRANCHING_TIME;
        proteolyticTime             =   PROFILE_CUSTOM_PROTEOLYTIC_TIME;
        betaAmylaseTime             =   PROFILE_CUSTOM_BETAAMYLASE_TIME;
        alphaAmylaseTime            =   PROFILE_CUSTOM_ALPHAAMYLASE_TIME;
        mashoutTime                 =   PROFILE_CUSTOM_MASHOUT_TIME;
        recirculationTime           =   PROFILE_CUSTOM_RECIRCULATION_TIME;
        spargeTime                  =   PROFILE_CUSTOM_SPARGE_TIME;
        boilTime                    =   PROFILE_CUSTOM_BOIL_TIME;
        coolingTime                 =   PROFILE_CUSTOM_COOLING_TIME;

        startpointTemperature       =   PROFILE_CUSTOM_STARTPOINT_TEMPERATURE;
        betaGlucanaseTemperature    =   PROFILE_CUSTOM_BETAGLUCANASE_TEMPERATURE;
        debranchingTemperature      =   PROFILE_CUSTOM_DEBRANCHING_TEMPERATURE;
        proteolyticTemperature      =   PROFILE_CUSTOM_PROTEOLYTIC_TEMPERATURE;
        betaAmylaseTemperature      =   PROFILE_CUSTOM_BETAAMYLASE_TEMPERATURE;
        alphaAmylaseTemperature     =   PROFILE_CUSTOM_ALPHAAMYLASE_TEMPERATURE;
        mashoutTemperature          =   PROFILE_CUSTOM_MASHOUT_TEMPERATURE;
        recirculationTemperature    =   PROFILE_CUSTOM_RECIRCULATION_TEMPERATURE;
        spargeTemperature           =   PROFILE_CUSTOM_SPARGE_TEMPERATURE;
        boilTemperature             =   PROFILE_CUSTOM_BOIL_TEMPERATURE;
        coolingTemperature          =   PROFILE_CUSTOM_COOLING_TEMPERATURE;

        backToStatus();

        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
923
    case eBeerProfileMenu_Back: {
924 925
        eMenuType = eMenuType_Main;
        repaint = true;
926

927 928 929 930 931 932
        // reset operation state | INPUT : eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep
        //xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenuPosition, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMainMenu._position, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );

        break;
      }
933
    default: {
934
      }
935
  }
936

João Lino's avatar
Rel.3  
João Lino committed
937
  eBeerProfileMenuSelection = eBeerProfileMenu_NULL;
938 939
}

João Lino's avatar
João Lino committed
940 941
void xStartStage( unsigned long *stageTime, int *stageTemperature, eCookingStages nextStage, bool bPurgePump, bool bSetFinalYield, bool bSetTime, bool bSetTemperature ) {
  xSafeHardwarePowerOff();                      // Stop anything that might be still going on
942 943 944 945 946 947 948 949 950 951 952 953 954 955

  if (bSetFinalYield) {
    finalYield = xSetFinalYield( finalYield );
  }
  if (bSetTime) {
    (*stageTime) = getTimer( clockCounter / 1000, (*stageTime) );
  }
  if (bSetTemperature) {
    (*stageTemperature) = xSetTemperature( (*stageTemperature) );
  }
  if (bPurgePump) {
    xPurgePump();
  }

João Lino's avatar
João Lino committed
956
  startBrewing();
João Lino's avatar
João Lino committed
957
  xSetupStage( nextStage );
João Lino's avatar
João Lino committed
958
  backToStatus();
João Lino's avatar
João Lino committed
959 960 961 962 963
}

void xStartStageHeadless( eCookingStages nextStage, bool bPurgePump ) {
  xStartStage( NULL, NULL, nextStage, bPurgePump, false, false, false );
}
João Lino's avatar
João Lino committed
964

João Lino's avatar
João Lino committed
965 966
void xStartStageInteractive( unsigned long *stageTime, int *stageTemperature, eCookingStages nextStage ) {
  xStartStage( stageTime, stageTemperature, nextStage, true, true, true, true );
João Lino's avatar
João Lino committed
967 968 969
}

void runStartFromStageSelection() {
970
  switch (eStartFromStageMenuSelection) {
João Lino's avatar
João Lino committed
971
    case eStageMenu_Startpoint: {
972 973 974
        xStartStageInteractive( &startpointTime, &startpointTemperature, eCookingStage_Startpoint );
        break;
      }
João Lino's avatar
João Lino committed
975
    case eStageMenu_BetaGlucanase: {
976 977 978
        xStartStageInteractive( &betaGlucanaseTime, &betaGlucanaseTemperature, eCookingStage_BetaGlucanase );
        break;
      }
João Lino's avatar
João Lino committed
979
    case eStageMenu_Debranching: {
980 981 982
        xStartStageInteractive( &debranchingTime, &debranchingTemperature, eCookingStage_Debranching );
        break;
      }
João Lino's avatar
João Lino committed
983
    case eStageMenu_Proteolytic: {
984 985 986
        xStartStageInteractive( &proteolyticTime, &proteolyticTemperature, eCookingStage_Proteolytic );
        break;
      }
João Lino's avatar
João Lino committed
987
    case eStageMenu_BetaAmylase: {
988 989 990
        xStartStageInteractive( &betaAmylaseTime, &betaAmylaseTemperature, eCookingStage_BetaAmylase );
        break;
      }
João Lino's avatar
João Lino committed
991
    case eStageMenu_AlphaAmylase: {
992 993 994
        xStartStageInteractive( &alphaAmylaseTime, &alphaAmylaseTemperature, eCookingStage_AlphaAmylase );
        break;
      }
João Lino's avatar
João Lino committed
995
    case eStageMenu_Mashout: {
996 997 998
        xStartStageInteractive( &mashoutTime, &mashoutTemperature, eCookingStage_Mashout );
        break;
      }
João Lino's avatar
João Lino committed
999
    case eStageMenu_Recirculation: {
1000 1001 1002
        xStartStageInteractive( &recirculationTime, &recirculationTemperature, eCookingStage_Recirculation );
        break;
      }
João Lino's avatar
João Lino committed
1003
    case eStageMenu_Sparge: {
1004 1005 1006
        xStartStageInteractive( &spargeTime, &spargeTemperature, eCookingStage_Sparge );
        break;
      }
João Lino's avatar
João Lino committed
1007
    case eStageMenu_Boil: {
1008 1009 1010
        xStartStageInteractive( &boilTime, &boilTemperature, eCookingStage_Boil );
        break;
      }
João Lino's avatar
João Lino committed
1011
    case eStageMenu_Cooling: {
1012 1013 1014
        xStartStageInteractive( &coolingTime, &coolingTemperature, eCookingStage_Cooling );
        break;
      }
João Lino's avatar
João Lino committed
1015
    case eStageMenu_Back: {
1016 1017 1018
        resetMenu( true );
        break;
      }
João Lino's avatar
João Lino committed
1019
    default: {
1020
      }
João Lino's avatar
João Lino committed
1021 1022 1023 1024
  }
  eStartFromStageMenuSelection = eStageMenu_NULL;
}

João Lino's avatar
Rel.3  
João Lino committed
1025
void runMainMenuSelection() {
1026 1027
  switch (mdMainMenu._selection) {
  //switch (eMainMenuSelection) {
João Lino's avatar
João Lino committed
1028
    case eMainMenu_GO: {
1029 1030 1031
        xStartStage( NULL, NULL, eCookingStage_Startpoint, true, true, false, false );
        break;
      }
João Lino's avatar
João Lino committed
1032
    case eMainMenu_GO_FROM_STAGE: {
1033 1034 1035 1036 1037
        eMenuType = eMenuType_StartFromStage;
        repaint = true;
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eBeerProfileMenuPosition, MENU_SIZE_PROFILES_MENU - 1, 1, 1, 0 );
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1038
    case eMainMenu_STOP: {
1039 1040 1041 1042
        stopBrewing();
        backToStatus();
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1043
    case eMainMenu_SKIP: {
1044 1045 1046 1047
        cookTime = 0;
        backToStatus();
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1048
    case eMainMenu_BeerProfile: {
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
        eMenuType = eMenuType_BeerProfile;
        repaint = true;
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eBeerProfileMenuPosition, MENU_SIZE_PROFILES_MENU - 1, 1, 1, 0 );
        break;
      }
    case eMainMenu_Stage: {
        eMenuType = eMenuType_Stage;
        repaint = true;
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eStageMenuPosition, MENU_SIZE_STAGE_MENU - 1, 1, 1, 0 );
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1060
    case eMainMenu_Malt: {
1061 1062 1063 1064 1065
        eMenuType = eMenuType_Malt;
        repaint = true;
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMaltMenuPosition, MENU_SIZE_MALT_MENU - 1, 1, 1, 0 );
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1066
    case eMainMenu_Hops: {
1067 1068 1069
        backToStatus();
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1070
    case eMainMenu_Clean: {
1071 1072 1073
        xStartStageHeadless( eCookingStage_Clean, true );
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1074
    case eMainMenu_Purge: {
1075 1076 1077
        xStartStageHeadless( eCookingStage_Purge, true );
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1078
    case eMainMenu_Settings: {
1079 1080 1081 1082 1083
        eMenuType = eMenuType_Settings;
        repaint = true;
        xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eSettingsMenuPosition, MENU_SIZE_SETTINGS_MENU - 1, 1, 1, 0 );
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1084
    case eMainMenu_Back: {
1085 1086 1087
        backToStatus();
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1088
    default: {
1089
      }
João Lino's avatar
Rel.3  
João Lino committed
1090
  }
1091 1092
  mdMainMenu._selection = eMainMenu_NULL;
  //eMainMenuSelection = eMainMenu_NULL;
1093 1094
}

João Lino's avatar
João Lino committed
1095
void xCountTheTime( int temperatureMarginRange, boolean bMaximumOfUpDown ) {
1096
  unsigned long now = millis();
João Lino's avatar
João Lino committed
1097 1098

  // Get current maximum sensed temperaure
João Lino's avatar
Rel.3  
João Lino committed
1099
  double temperatureCount = 0;
1100
  if ( bMaximumOfUpDown ) {
João Lino's avatar
Rel.3  
João Lino committed
1101 1102
    float tup = upPT100.getCurrentTemperature();
    float tdown = downPT100.getCurrentTemperature();
1103
    if (tup > tdown) {
João Lino's avatar
João Lino committed
1104
      temperatureCount = tdown;
João Lino's avatar
Rel.3  
João Lino committed
1105 1106
    }
    else {
João Lino's avatar
João Lino committed
1107
      temperatureCount = tup;
João Lino's avatar
Rel.3  
João Lino committed
1108 1109 1110 1111
    }
  } else {
    temperatureCount = basePT100.getCurrentTemperature();
  }
João Lino's avatar
João Lino committed
1112

João Lino's avatar
João Lino committed
1113 1114
  // Ignote time ticks if temperature is not within the acceptable margin for this stage
  unsigned long elapsedTime = now - clockLastUpdate;
1115
  if ( temperatureCount < (cookTemperature - temperatureMarginRange) ) {
João Lino's avatar
Rel.3  
João Lino committed
1116
    clockIgnore += elapsedTime;
João Lino's avatar
João Lino committed
1117
  }
1118

João Lino's avatar
João Lino committed
1119
  // Calculate the remaining time on the clock
João Lino's avatar
João Lino committed
1120
  clockCounter = cookTime * 1000 - (elapsedTime - clockIgnore);
João Lino's avatar
João Lino committed
1121

João Lino's avatar
João Lino committed
1122
  // Don't let clock get bellow 0
João Lino's avatar
Rel.3  
João Lino committed
1123 1124 1125 1126 1127 1128
  if ( clockCounter < 0 ) {
    clockCounter = 0;
  }

  clockLastUpdate = now;

1129
#ifdef DEBUG_OFF
1130 1131
  debugPrintFunction("xCountTheTime");
  debugPrintVar("millis()", now);
João Lino's avatar
João Lino committed
1132
  debugPrintVar("cookTime", cookTime);
1133 1134
  debugPrintVar("clockStartTime", clockStartTime);
  debugPrintVar("clockIgnore", clockIgnore);
1135 1136
  debugPrintVar("clockCounter", clockCounter);
#endif
1137 1138 1139
}

bool isTimeLeft() {
1140
  if ( clockCounter > 0 ) {
1141
    return true;
João Lino's avatar
João Lino committed
1142
  }
1143
  return false;
1144 1145
}

1146
//HEATING_ELEMENT_MAX_WATTAGE / HEATING_ELEMENT_AC_FREQUENCY_HZ
1147 1148
double ulWattToWindowTime( double ulAppliedWatts ) {
  double ulPulsesRequired = ulAppliedWatts / dWattPerPulse;
1149
  return (double)iWindowSize / 1000.0 * ulPulsesRequired * 1000.0 / HEATING_ELEMENT_AC_FREQUENCY_HZ;
1150 1151
}

João Lino's avatar
João Lino committed
1152
bool xRegulateTemperature( boolean bMaximumOfUpDown ) {
João Lino's avatar
Rel.3  
João Lino committed
1153
  double difference = 0;
João Lino's avatar
João Lino committed
1154 1155
  bool overTemperature = false;
  double wattage = 0.0;
1156

João Lino's avatar
João Lino committed
1157 1158 1159
  float tup = upPT100.getCurrentTemperature();
  float tdown = downPT100.getCurrentTemperature();
  float tbase = basePT100.getCurrentTemperature();
João Lino's avatar
Rel.3  
João Lino committed
1160

1161 1162
  if ( bMaximumOfUpDown ) {
    if (tup > tdown) {
João Lino's avatar
Rel.3  
João Lino committed
1163 1164 1165 1166 1167 1168
      difference = cookTemperature - tup;
    }
    else {
      difference = cookTemperature - tdown;
    }

1169
    if (tbase > cookTemperature && (tbase >= (PUMP_TEMPERATURE_MAX_OPERATION - 2.0) || difference >= 5.0)) {
João Lino's avatar
João Lino committed
1170
      difference = cookTemperature - tbase;
João Lino's avatar
Rel.3  
João Lino committed
1171 1172
    }

1173
    if ( (tbase < cookTemperature) && (difference < (cookTemperature - tbase)) ) {
João Lino's avatar
Rel.3  
João Lino committed
1174 1175 1176
      difference = cookTemperature - tbase;
    }
  } else {
João Lino's avatar
João Lino committed
1177
    difference = cookTemperature - tbase;
João Lino's avatar
Rel.3  
João Lino committed
1178 1179
  }

João Lino's avatar
João Lino committed
1180
  // Deviation between the cook temperature set and the cook temperature measured
1181
  if ( difference < 0.0 ) {
João Lino's avatar
João Lino committed
1182 1183 1184
    difference = difference * (-1.0);
    overTemperature = true;
  }
1185

João Lino's avatar
João Lino committed
1186
  // Calculate applied wattage, based on the distance from the target temperature
1187
  if ( overTemperature ) {
João Lino's avatar
João Lino committed
1188 1189 1190
    // turn it off
    wattage = 0.0;
  } else {
João Lino's avatar
João Lino committed
1191
    //if(difference <= 0.1) {
1192
    // turn it off
João Lino's avatar
João Lino committed
1193 1194
    //  wattage = 0.0;
    //} else {
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
    if (difference <= 0.5) {
      // pulse lightly at 500 watt
      if (cookTemperature > 99.0) {
        wattage = 2000.0;
      }
      else {
        if (cookTemperature > 70.0) {
          wattage = 1000.0;
        }
        else {
          wattage = 500.0;
        }
      }
    } else {
      if (difference <= 1.0) {
        // pulse moderately at 1000 watt
        if (cookTemperature > 99.0) {
João Lino's avatar
João Lino committed
1212
          wattage = 2000.0;
João Lino's avatar
Rel.3  
João Lino committed
1213 1214
        }
        else {
1215
          wattage = 1000.0;
João Lino's avatar
Rel.3  
João Lino committed
1216
        }
1217

João Lino's avatar
João Lino committed
1218
      } else {
1219 1220 1221
        if (difference <= 3.0) {
          // pulse hardly at 2000 watt
          wattage = 2000.0;
João Lino's avatar
João Lino committed
1222
        } else {
1223 1224
          //pulse constantly at HEATING_ELEMENT_MAX_WATTAGE watt
          wattage = HEATING_ELEMENT_MAX_WATTAGE;
João Lino's avatar
João Lino committed
1225 1226
        }
      }
1227
    }
João Lino's avatar
João Lino committed
1228
    //}
João Lino's avatar
João Lino committed
1229
  }
1230

João Lino's avatar
João Lino committed
1231
  // Update the recorded time for the begining of the window, if the previous window has passed
1232
  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
1233
    windowStartTime += iWindowSize;
1234
  }
1235

João Lino's avatar
João Lino committed
1236
  // Apply wattage to the element at the right time
1237 1238
  if ( ulWattToWindowTime( wattage ) > (millis() - windowStartTime) ) {
    digitalWrite(HEATING_ELEMENT_OUTPUT_PIN, HIGH);
João Lino's avatar
Rel.3  
João Lino committed
1239
    bStatusElement = true;
João Lino's avatar
João Lino committed
1240
  } else {
1241
    digitalWrite(HEATING_ELEMENT_OUTPUT_PIN, LOW);
João Lino's avatar
Rel.3  
João Lino committed
1242
    bStatusElement = false;
João Lino's avatar
João Lino committed
1243
  }
1244

1245
#ifdef DEBUG_OFF
1246
  //debugPrintFunction("xRegulateTemperature");
1247
  debugPrintVar("difference", difference);
1248
  //debugPrintVar("overTemperature", overTemperature);
1249
  debugPrintVar("wattage", wattage);
1250 1251 1252
  //debugPrintVar("ulWattToWindowTime( wattage )", ulWattToWindowTime( wattage ) );
  //debugPrintVar("millis()", millis());
  //debugPrintVar("windowStartTime", windowStartTime);
1253 1254
  //debugPrintVar("test", ulWattToWindowTime( wattage ) > (millis() - windowStartTime) );
#endif
João Lino's avatar
Rel.3  
João Lino committed
1255 1256 1257
}

void xPurgePump() {
1258
  for (int i = 0; i < 2; i++) {
João Lino's avatar
João Lino committed
1259
    analogWrite(PUMP_PIN, PUMP_SPEED_MAX_MOSFET);  // analogWrite values from 0 to 255
João Lino's avatar
Rel.3  
João Lino committed
1260
    delay(1000);
João Lino's avatar
João Lino committed
1261
    analogWrite(PUMP_PIN, PUMP_SPEED_STOP_MOSFET);  // analogWrite values from 0 to 255
João Lino's avatar
Rel.3  
João Lino committed
1262 1263
    delay(1500);
  }
1264 1265
}

1266
bool xRegulatePumpSpeed() {
João Lino's avatar
Rel.3  
João Lino committed
1267 1268
  //  analogWrite(PUMP_PIN, iPumpSpeed);  // analogWrite values from 0 to 255

1269
  if (basePT100.getCurrentTemperature() > PUMP_TEMPERATURE_MAX_OPERATION) {
João Lino's avatar
João Lino committed
1270
    analogWrite(PUMP_PIN, PUMP_SPEED_STOP_MOSFET);  // analogWrite values from 0 to 255
1271

João Lino's avatar
João Lino committed
1272 1273 1274
    basePT100.setPumpStatus( false );
    upPT100.setPumpStatus( false );
    downPT100.setPumpStatus( false );
1275 1276
  }
  else {
João Lino's avatar
Rel.3  
João Lino committed
1277 1278
    analogWrite(PUMP_PIN, iPumpSpeed);  // analogWrite values from 0 to 255

João Lino's avatar
João Lino committed
1279 1280 1281
    basePT100.setPumpStatus( true );
    upPT100.setPumpStatus( true );
    downPT100.setPumpStatus( true );
1282
  }
1283 1284
}

1285
void xWarnClockEnded() {
1286
  sing(MELODY_SUPER_MARIO_START, PIEZO_PIN);
1287 1288
}

João Lino's avatar
Rel.3  
João Lino committed
1289 1290 1291 1292
void xWarnCookEnded() {
  sing(MELODY_UNDERWORLD_SHORT, PIEZO_PIN);
}

João Lino's avatar
João Lino committed
1293
void xPrepareForStage( int stageTime, int stageTemperature, int stagePumpSpeed, eCookingStages stage ) {
1294
#ifdef DEBUG_OFF
João Lino's avatar
João Lino committed
1295
  debugPrintFunction("xPrepareForStage");
João Lino's avatar
Rel.3  
João Lino committed
1296
  debugPrintVar("cookingStage", stage);
1297
#endif
João Lino's avatar
Rel.3  
João Lino committed
1298

João Lino's avatar
João Lino committed
1299
  // Reset the clock
João Lino's avatar
João Lino committed
1300 1301 1302 1303
  unsigned long now = millis();
  clockStartTime  = now;
  clockLastUpdate = now;
  clockIgnore     = 0;
1304

João Lino's avatar
João Lino committed
1305 1306 1307 1308
  iPumpSpeed      = stagePumpSpeed;         // Set the pump speed
  cookingStage    = stage;                  // Set Stage
  cookTime        = stageTime;              // Set the clock
  cookTemperature = stageTemperature;       // Set the target temperature
1309 1310
}

João Lino's avatar
João Lino committed
1311
void xSetupStage(eCookingStages nextStage) {
1312
#ifdef DEBUG_OFF
João Lino's avatar
João Lino committed
1313
  debugPrintFunction("xSetupStage");
João Lino's avatar
Rel.3  
João Lino committed
1314
  debugPrintVar("cookingStage", nextStage);
1315
#endif
João Lino's avatar
João Lino committed
1316 1317

  // Operate the machine according to the current mode
1318
  switch (nextStage) {
João Lino's avatar
João Lino committed
1319
    case eCookingStage_Startpoint: {
1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353
        switch (beerProfile) {
          case eBeerProfile_Trigo: {
              float wheatAmount = 0.05 * ((float) finalYield);
              float pilsnerAmount = 0.2 * ((float) finalYield);
              String say = "Cruch ";
              say += String(wheatAmount);
              say += String("Kg of Wheat and ");
              say += String(pilsnerAmount);
              say += String("Kg of Pilsner Malt into a pot.");

              xWaitForAction("Malt", say);
              repaint = true;
              break;
            }
          case eBeerProfile_IPA: {
              float caramelAmount = 0.013157895 * ((float) finalYield);
              float wheatAmount = 0.060526316 * ((float) finalYield);
              float pilsnerAmount = 0.115789474 * ((float) finalYield);
              float munichAmount = 0.028947368 * ((float) finalYield);
              String say = "Cruch ";
              say += String(caramelAmount);
              say += String("Kg of Caramel 120, ");
              say += String(wheatAmount);
              say += String("Kg of Wheat, ");
              say += String(pilsnerAmount);
              say += String("Kg of Pilsner, ");
              say += String(munichAmount);
              say += String("Kg of Munich into a pot.");

              xWaitForAction("Malt", say);
              repaint = true;
              break;
            }
          default: {
João Lino's avatar
Rel.3  
João Lino committed
1354

1355
            }
João Lino's avatar
Rel.3  
João Lino committed
1356 1357
        }

1358 1359
        // Make sure there is water
        xWaitForAction("Water", "Make sure there is water in the machine before start cooking.");
João Lino's avatar
Rel.3  
João Lino committed
1360

1361 1362 1363 1364
        repaint = true;
        xPrepareForStage( startpointTime, startpointTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Startpoint );
        break;
      }
João Lino's avatar
João Lino committed
1365
    case eCookingStage_BetaGlucanase: {
1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399
        switch (beerProfile) {
          case eBeerProfile_Trigo: {
              float wheatAmount = 0.05 * ((float) finalYield);
              float pilsnerAmount = 0.2 * ((float) finalYield);
              String say = "Put ";
              say += String(wheatAmount);
              say += String("Kg of Wheat and ");
              say += String(pilsnerAmount);
              say += String("Kg of Pilsner Malt in.");

              xWaitForAction("Malt", say);
              repaint = true;
              break;
            }
          case eBeerProfile_IPA: {
              float caramelAmount = 0.013157895 * ((float) finalYield);
              float wheatAmount = 0.060526316 * ((float) finalYield);
              float pilsnerAmount = 0.115789474 * ((float) finalYield);
              float munichAmount = 0.028947368 * ((float) finalYield);
              String say = "Cruch ";
              say += String(caramelAmount);
              say += String("Kg of Caramel 120, ");
              say += String(wheatAmount);
              say += String("Kg of Wheat, ");
              say += String(pilsnerAmount);
              say += String("Kg of Pilsner, ");
              say += String(munichAmount);
              say += String("Kg of Munich into a pot.");

              xWaitForAction("Malt", say);
              repaint = true;
              break;
            }
          default: {}
João Lino's avatar
João Lino committed
1400
        }
1401 1402
        xPrepareForStage( betaGlucanaseTime, betaGlucanaseTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_BetaGlucanase );
        break;
João Lino's avatar
Rel.3  
João Lino committed
1403
      }
João Lino's avatar
João Lino committed
1404
    case eCookingStage_Debranching: {
1405 1406 1407
        xPrepareForStage( debranchingTime, debranchingTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Debranching );
        break;
      }
João Lino's avatar
João Lino committed
1408
    case eCookingStage_Proteolytic: {
1409 1410 1411
        xPrepareForStage( proteolyticTime, proteolyticTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Proteolytic );
        break;
      }
João Lino's avatar
João Lino committed
1412
    case eCookingStage_BetaAmylase: {
1413 1414 1415
        xPrepareForStage( betaAmylaseTime, betaAmylaseTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_BetaAmylase );
        break;
      }
João Lino's avatar
João Lino committed
1416
    case eCookingStage_AlphaAmylase: {
1417 1418 1419
        xPrepareForStage( alphaAmylaseTime, alphaAmylaseTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_AlphaAmylase );
        break;
      }
João Lino's avatar
João Lino committed
1420
    case eCookingStage_Mashout: {
1421 1422 1423
        xPrepareForStage( mashoutTime, mashoutTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Mashout );
        break;
      }
João Lino's avatar
João Lino committed
1424
    case eCookingStage_Recirculation: {
1425 1426 1427 1428 1429
        xWaitForAction("Sparge Water", "Start heating your sparge water.");
        repaint = true;
        xPrepareForStage( recirculationTime, recirculationTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Recirculation );
        break;
      }
João Lino's avatar
João Lino committed
1430
    case eCookingStage_Sparge: {
1431 1432 1433 1434 1435
        xWaitForAction("Sparge Water", "Start pouring the sparge water.");
        repaint = true;
        xPrepareForStage( spargeTime, spargeTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Sparge );
        break;
      }
João Lino's avatar
João Lino committed
1436
    case eCookingStage_Boil: {
1437 1438 1439
        switch (beerProfile) {
          case eBeerProfile_Trigo: {
              String say = "Get ";
João Lino's avatar
Rel.3  
João Lino committed
1440

1441 1442
              float hopAmount = 0.8 * ((float) finalYield);
              say += String(hopAmount);
João Lino's avatar
Rel.3  
João Lino committed
1443

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

1446
              xWaitForAction("Hops", say);
João Lino's avatar
Rel.3  
João Lino committed
1447

1448 1449 1450 1451
              break;
            }
          case eBeerProfile_IPA: {
              String say = "Get ";
João Lino's avatar
João Lino committed
1452

1453 1454
              float hopAmount = 0.8 * ((float) finalYield);
              say += String(hopAmount);
João Lino's avatar
João Lino committed
1455

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

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

1460 1461 1462 1463
              break;
            }
          default: {
              xWaitForAction("Hops", "Add the hops in the right order, at the right time.");
João Lino's avatar
Rel.3  
João Lino committed
1464

1465
            }
João Lino's avatar
Rel.3  
João Lino committed
1466 1467
        }

1468
        repaint = true;
João Lino's avatar
Rel.3  
João Lino committed
1469

1470 1471 1472 1473 1474
        // A basic operation for a basic stage
        xPrepareForStage( boilTime, boilTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Boil );

        break;
      }
João Lino's avatar
João Lino committed
1475
    case eCookingStage_Cooling: {
1476 1477
        // Make sure there is water
        xWaitForAction("Coil", "Add the coil and connect it to the main water supply.");
João Lino's avatar
Rel.3  
João Lino committed
1478

1479
        repaint = true;
João Lino's avatar
Rel.3  
João Lino committed
1480

1481 1482
        // A basic operation for a basic stage
        xPrepareForStage( coolingTime, coolingTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Cooling );
João Lino's avatar
Rel.3  
João Lino committed
1483

1484 1485
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1486
    case eCookingStage_Clean: {
1487 1488
        // Make sure there is water
        xWaitForAction("Water", "Add 13 liters.");
João Lino's avatar
Rel.3  
João Lino committed
1489

1490 1491
        // Make sure there is water
        xWaitForAction("Star San HB", "Add 0.89oz/26ml.");
João Lino's avatar
Rel.3  
João Lino committed
1492

1493
        repaint = true;
João Lino's avatar
Rel.3  
João Lino committed
1494

1495 1496
        // A basic operation for a basic stage
        xPrepareForStage( cleaningTime, cleaningTemperature, PUMP_SPEED_MAX_MOSFET, eCookingStage_Clean );
João Lino's avatar
João Lino committed
1497

1498 1499
        break;
      }
João Lino's avatar
João Lino committed
1500
    case eCookingStage_Purge: {
1501 1502
        // A basic operation for a basic stage
        xPrepareForStage( 0, 0, PUMP_SPEED_MAX_MOSFET, eCookingStage_Purge );
João Lino's avatar
João Lino committed
1503

1504
        xRegulatePumpSpeed();
João Lino's avatar
João Lino committed
1505

1506 1507
        break;
      }
João Lino's avatar
João Lino committed
1508
    case eCookingStage_Done: {
1509 1510
        // A basic operation for a basic stage
        xPrepareForStage( 0, 0, PUMP_SPEED_STOP_MOSFET, eCookingStage_Done );
João Lino's avatar
João Lino committed
1511

1512 1513
        break;
      }
João Lino's avatar
João Lino committed
1514
  }
1515 1516 1517
}

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

João Lino's avatar
João Lino committed
1521 1522
  // Warn the user a stage has ended
  xWarnClockEnded();
1523

João Lino's avatar
João Lino committed
1524
  // Reset global stage variables
João Lino's avatar
João Lino committed
1525
  xSetupStage( nextStage );
1526 1527
}

João Lino's avatar
João Lino committed
1528
void xBasicStageOperation( int iStageTime, int iStageTemperature, int iStageTemperatureRange, eCookingStages nextStage, boolean bMaximumOfUpDown ) {
João Lino's avatar
João Lino committed
1529

João Lino's avatar
João Lino committed
1530
  // Account for time spent at the target temperature | Input 1: range in ºC within which the target temperature is considered to be reached
1531
#ifdef DEBUG_OFF
João Lino's avatar
João Lino committed
1532
  xCountTheTime( iStageTemperatureRange, false );
1533
#else
João Lino's avatar
João Lino committed
1534
  xCountTheTime( iStageTemperatureRange, bMaximumOfUpDown );
1535 1536 1537
#endif

  if ( isTimeLeft() ) {
João Lino's avatar
João Lino committed
1538 1539 1540 1541 1542
    // Do temperature control
    xRegulateTemperature( bMaximumOfUpDown );

    // Do flow control
    xRegulatePumpSpeed();
1543

João Lino's avatar
João Lino committed
1544
  } else {
1545
#ifdef DEBUG_OFF
João Lino's avatar
João Lino committed
1546 1547
    debugPrintFunction("xBasicStageOperation");
    debugPrintVar("clockCounter", clockCounter);
1548 1549
#endif

João Lino's avatar
João Lino committed
1550 1551 1552
    // Continue to the next stage, there is nothing to do, in this stage
    xTransitionIntoStage( nextStage );
    return;
João Lino's avatar
João Lino committed
1553
  }
1554

João Lino's avatar
João Lino committed
1555
  return;
1556 1557
}

João Lino's avatar
Rel.3  
João Lino committed
1558
void xManageMachineSystems() {
1559

1560
#ifdef DEBUG
João Lino's avatar
Rel.3  
João Lino committed
1561 1562
  Serial.print(millis());
  Serial.print(",");
1563
  if (cooking) {
João Lino's avatar
Rel.3  
João Lino committed
1564 1565 1566 1567 1568 1569 1570 1571
    Serial.print("1");
  }
  else {
    Serial.print("0");
  }
  Serial.print(",");
  Serial.print(cookTemperature);
  Serial.print(",");
1572
  if (bStatusElement) {
João Lino's avatar
Rel.3  
João Lino committed
1573 1574 1575 1576 1577 1578
    Serial.print("1");
  }
  else {
    Serial.print("0");
  }
  Serial.print(",");
1579
#endif
1580 1581

  // Measure temperature, for effect
João Lino's avatar
João Lino committed
1582 1583 1584
  basePT100.measure(false);
  upPT100.measure(false);
  downPT100.measure(true);
1585 1586

  // If cooking is done, return (this is a nice place to double check safety and ensure the cooking parts aren't on.
1587
  if (!cooking) {
João Lino's avatar
João Lino committed
1588
    xSafeHardwarePowerOff();
1589

1590 1591
    return;
  }
1592

João Lino's avatar
João Lino committed
1593
  // Operate the machine according to the current mode
1594
  switch (cookingStage) {
João Lino's avatar
João Lino committed
1595
    case eCookingStage_Startpoint: {
1596 1597 1598 1599 1600
        // A basic operation for a basic stage
        xBasicStageOperation( startpointTime, startpointTemperature, 0, eCookingStage_BetaGlucanase, false);

        break;
      }
João Lino's avatar
João Lino committed
1601
    case eCookingStage_BetaGlucanase: {
1602 1603 1604 1605 1606
        // A basic operation for a basic stage
        xBasicStageOperation( betaGlucanaseTime, betaGlucanaseTemperature, 3, eCookingStage_Debranching, true );

        break;
      }
João Lino's avatar
João Lino committed
1607
    case eCookingStage_Debranching: {
1608 1609 1610 1611 1612
        // A basic operation for a basic stage
        xBasicStageOperation( debranchingTime, debranchingTemperature, 3, eCookingStage_Proteolytic, true );

        break;
      }
João Lino's avatar
João Lino committed
1613
    case eCookingStage_Proteolytic: {
1614 1615 1616 1617 1618
        // A basic operation for a basic stage
        xBasicStageOperation( proteolyticTime, proteolyticTemperature, 3, eCookingStage_BetaAmylase, true );

        break;
      }
João Lino's avatar
João Lino committed
1619
    case eCookingStage_BetaAmylase: {
1620 1621 1622 1623 1624
        // A basic operation for a basic stage
        xBasicStageOperation( betaAmylaseTime, betaAmylaseTemperature, 4, eCookingStage_AlphaAmylase, true );

        break;
      }
João Lino's avatar
João Lino committed
1625
    case eCookingStage_AlphaAmylase: {
1626 1627 1628 1629 1630
        // A basic operation for a basic stage
        xBasicStageOperation( alphaAmylaseTime, alphaAmylaseTemperature, 2, eCookingStage_Mashout, true );

        break;
      }
João Lino's avatar
João Lino committed
1631
    case eCookingStage_Mashout: {
1632 1633 1634 1635 1636
        // A basic operation for a basic stage
        xBasicStageOperation( mashoutTime, mashoutTemperature, 1, eCookingStage_Recirculation, true );

        break;
      }
João Lino's avatar
João Lino committed
1637
    case eCookingStage_Recirculation: {
1638 1639 1640 1641 1642
        // A basic operation for a basic stage
        xBasicStageOperation( recirculationTime, recirculationTemperature, 1, eCookingStage_Sparge, true );

        break;
      }
João Lino's avatar
João Lino committed
1643
    case eCookingStage_Sparge: {
1644 1645 1646 1647 1648
        // A basic operation for a basic stage
        xBasicStageOperation( spargeTime, spargeTemperature, 3, eCookingStage_Boil, false );

        break;
      }
João Lino's avatar
João Lino committed
1649
    case eCookingStage_Boil: {
1650 1651 1652 1653 1654
        // A basic operation for a basic stage
        xBasicStageOperation( boilTime, boilTemperature, 2, eCookingStage_Cooling, false );

        break;
      }
João Lino's avatar
João Lino committed
1655
    case eCookingStage_Cooling: {
1656 1657
        // A basic operation for a basic stage
        xBasicStageOperation( coolingTime, coolingTemperature, 0, eCookingStage_Done, false );
João Lino's avatar
Rel.3  
João Lino committed
1658

1659 1660
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1661
    case eCookingStage_Clean: {
1662 1663
        // A basic operation for a basic stage
        xBasicStageOperation( cleaningTime, cleaningTemperature, 0, eCookingStage_Done, false );
1664

1665 1666
        break;
      }
1667
    case eCookingStage_Purge: {
1668 1669 1670
        // A basic operation for a basic stage
        //xBasicStageOperation( coolingTime, coolingTemperature, 1, eCookingStage_Done );
        iPumpSpeed = PUMP_SPEED_MAX_MOSFET;
1671

1672
        xRegulatePumpSpeed();
1673

1674 1675
        break;
      }
João Lino's avatar
Rel.3  
João Lino committed
1676
    case eCookingStage_Done: {
1677 1678
        // Update cooking state
        stopBrewing();
João Lino's avatar
Rel.3  
João Lino committed
1679

1680 1681
        // Ask for screen refresh
        repaint = true;
João Lino's avatar
Rel.3  
João Lino committed
1682

1683 1684 1685 1686 1687
        // Warn the user that the cooking is done
        xWarnCookEnded();

        break;
      }
João Lino's avatar
João Lino committed
1688
  }
1689 1690 1691 1692 1693
}

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

void startBrewing() {
1694 1695
  //sing(MELODY_SUPER_MARIO, PIEZO_PIN);

1696 1697 1698 1699 1700 1701 1702
  cooking = true;
}

void stopBrewing() {
  cooking = false;
}

João Lino's avatar
João Lino committed
1703 1704 1705
void resetMenu( boolean requestRepaintPaint ) {
  eMenuType = eMenuType_Main;

1706
  if ( requestRepaintPaint ) {
João Lino's avatar
João Lino committed
1707 1708
    repaint = true;
  }
1709

João Lino's avatar
João Lino committed
1710
  // reset operation state | INPUT : eRotaryEncoderMode newMode, int newPosition, int newMaxPosition, int newMinPosition, int newSingleStep, int newMultiStep
1711 1712
  //xSetupRotaryEncoder( eRotaryEncoderMode_Menu, eMainMenuPosition, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );
  xSetupRotaryEncoder( eRotaryEncoderMode_Menu, mdMainMenu._position, MENU_SIZE_MAIN_MENU - 1, 1, 1, 0 );
João Lino's avatar
João Lino committed
1713 1714
}

1715 1716
void backToStatus() {
  lastInterruptTime = millis() - SETTING_MAX_INACTIVITY_TIME - 1;
João Lino's avatar
João Lino committed
1717
  resetMenu(true);
1718 1719 1720 1721
}
// #################################################### Helpers ##################################################################

// #################################################### Set Variables ##################################################################
João Lino's avatar
João Lino committed
1722
int getTimer( int initialValue, int defaultValue ) {
João Lino's avatar
João Lino committed
1723
  // 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
1724
  xSetupRotaryEncoder( eRotaryEncoderMode_Time, initialValue, 7200, 0, 1, 30 );
1725 1726

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

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

  while (true) {
1748
    // Check if pushbutton is pressed
1749
    if ((digitalRead(ROTARY_ENCODER_SW_PIN))) {
1750
      // Wait until switch is released
1751 1752
      while (digitalRead(ROTARY_ENCODER_SW_PIN)) {}

João Lino's avatar
João Lino committed
1753 1754
      // debounce
      delay(10);
1755

João Lino's avatar
João Lino committed
1756
      // Job is done, break the circle
1757
      break;
1758
    } else {
João Lino's avatar
João Lino committed
1759
      // Don't forget to keep an eye on the cooking
João Lino's avatar
Rel.3  
João Lino committed
1760
      xManageMachineSystems();
João Lino's avatar
João Lino committed
1761
    }
1762

1763
    // display current timer
service-config's avatar
Mixer  
service-config committed
1764 1765
    if (rotaryEncoderVirtualPosition != rotaryEncoderPreviousPosition) {
      rotaryEncoderPreviousPosition = rotaryEncoderVirtualPosition;
1766 1767 1768 1769 1770 1771
      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
1772 1773
        lcd.print(" ");
      }
1774
      if (minutes < 10) {
João Lino's avatar
João Lino committed
1775 1776 1777
        lcd.print(" ");
      }
      lcd.print("    ");
1778 1779
      lcd.print(minutes);
      lcd.print(":");
1780
      if (seconds < 10) {
1781 1782 1783 1784 1785 1786
        lcd.print("0");
      }
      lcd.print(seconds);
      lcd.println("                ");
    }
  }
1787

service-config's avatar
Mixer  
service-config committed
1788
  return rotaryEncoderVirtualPosition;
1789 1790
}

João Lino's avatar
João Lino committed
1791 1792 1793 1794 1795
int getTimer( int initialValue ) {
  return getTimer( initialValue, initialValue );
}

int getTemperature(int initialValue) {
1796

1797
  // set operation state
1798
  rotaryEncoderMode = eRotaryEncoderMode_Generic;
1799
  rotaryEncoderVirtualPosition = initialValue;
1800 1801

  // initialize variables
service-config's avatar
Mixer  
service-config committed
1802
  int rotaryEncoderPreviousPosition = 0;
1803

1804 1805
  // Setup Screen
  lcd.clear();
1806
  lcd.home();
1807
  lcd.print("Set Temperature");
1808
  lcd.setCursor (0, LCD_VERTICAL_RESOLUTION - 1);
1809
  lcd.print("       0 *C");
1810

1811
  rotaryEncoderMaxPosition = TEMPERATURE_SETTING_MAX_VALUE;
1812 1813

  while (true) {
1814
    // Check if pushbutton is pressed
1815
    if ((digitalRead(ROTARY_ENCODER_SW_PIN))) {
1816
      // Wait until switch is released
1817 1818
      while (digitalRead(ROTARY_ENCODER_SW_PIN)) {}

João Lino's avatar
João Lino committed
1819 1820
      // debounce
      delay(10);
1821

João Lino's avatar
João Lino committed
1822
      // Job is done, break the circle
1823
      break;
1824
    } else {
João Lino's avatar
João Lino committed
1825
      // Don't forget to keep an eye on the cooking
João Lino's avatar
Rel.3  
João Lino committed
1826
      xManageMachineSystems();
João Lino's avatar
João Lino committed
1827
    }
1828

1829
    // display current timer
service-config's avatar
Mixer  
service-config committed
1830 1831
    if (rotaryEncoderVirtualPosition != rotaryEncoderPreviousPosition) {
      rotaryEncoderPreviousPosition = rotaryEncoderVirtualPosition;
1832 1833

      lcd.setCursor (0, LCD_VERTICAL_RESOLUTION - 1);
1834
      lcd.print("     ");
1835
      if (rotaryEncoderVirtualPosition < 10) {
1836 1837 1838
        lcd.print("  ");
      }
      else {
1839
        if (rotaryEncoderVirtualPosition < 100) {
1840 1841 1842
          lcd.print(" ");
        }
      }
service-config's avatar
Mixer  
service-config committed
1843
      lcd.print(rotaryEncoderVirtualPosition);
1844 1845 1846 1847
      lcd.print(" *C");
      lcd.println("                ");
    }
  }
1848

service-config's avatar
Mixer  
service-config committed
1849
  return rotaryEncoderVirtualPosition;
1850 1851
}

1852
int xSetGenericValue(int initialValue, int minimumValue, int maximumValue, const char *valueName, const char *unit) {
João Lino's avatar
João Lino committed
1853
  // 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
1854
  xSetupRotaryEncoder( eRotaryEncoderMode_Generic, initialValue, maximumValue, minimumValue, 1, 5 );
1855 1856

  // initialize variables
service-config's avatar
Mixer  
service-config committed
1857
  int rotaryEncoderPreviousPosition = 0;
1858

1859 1860
  // Setup Screen
  lcd.clear();
1861 1862 1863 1864 1865
  lcd.home();
  lcd.print( "Set " );
  lcd.print( valueName );
  lcd.setCursor ( 0 , LCD_VERTICAL_RESOLUTION - 1 );
  lcd.print( "       0 " );
João Lino's avatar
João Lino committed
1866
  lcd.print( unit );
1867 1868

  while (true) {
1869 1870 1871
    // Check if pushbutton is pressed
    if ( digitalRead(ROTARY_ENCODER_SW_PIN) ) {
      // Wait until switch is released
1872 1873
      while ( digitalRead(ROTARY_ENCODER_SW_PIN) ) {}

João Lino's avatar
João Lino committed
1874 1875
      // debounce
      delay( 10 );
service-config's avatar
Mixer  
service-config committed
1876

João Lino's avatar
João Lino committed
1877
      // Job is done, break the circle
service-config's avatar
Mixer  
service-config committed
1878
      break;
1879
    } else {
João Lino's avatar
João Lino committed
1880
      // Don't forget to keep an eye on the cooking
João Lino's avatar
Rel.3  
João Lino committed
1881
      xManageMachineSystems();
João Lino's avatar
João Lino committed
1882
    }
1883

1884
    // Check if there was an update by the rotary encoder
1885
    if ( rotaryEncoderVirtualPosition != rotaryEncoderPreviousPosition ) {
service-config's avatar
Mixer  
service-config committed
1886
      rotaryEncoderPreviousPosition = rotaryEncoderVirtualPosition;
1887

1888 1889
      lcd.setCursor( 0, LCD_VERTICAL_RESOLUTION - 1 );
      lcd.print( "     " );
1890
      if ( rotaryEncoderVirtualPosition < 10 ) {
1891
        lcd.print( "  " );
1892 1893
      }
      else {
1894
        if ( rotaryEncoderVirtualPosition < 100 ) {
1895
          lcd.print( " " );
1896 1897
        }
      }
1898
      lcd.print( rotaryEncoderVirtualPosition );
1899 1900
      lcd.print( " " );
      lcd.print( unit );
1901
      lcd.println( "                " );
1902 1903
    }
  }
1904

1905
  return rotaryEncoderVirtualPosition;
1906 1907
}

1908
int xSetTemperature( int initialValue ) {
João Lino's avatar
João Lino committed
1909 1910 1911
  return xSetGenericValue( initialValue, TEMPERATURE_MIN_VALUE, TEMPERATURE_MAX_VALUE, "temperature", "*C" );
}

1912
int xSetFinalYield( int initialValue ) {
João Lino's avatar
João Lino committed
1913 1914 1915
  return xSetGenericValue( initialValue, SETTING_MACHINE_YIELD_CAPACITY_MIN, SETTING_MACHINE_YIELD_CAPACITY_MAX, "Final Yield", "l" );
}

João Lino's avatar
João Lino committed
1916 1917 1918 1919
unsigned long getInactivityTime() {
  unsigned long now = millis();
  unsigned long rotaryEncoderInactivityTime = now - lastInterruptTime;

1920
  if (rotaryEncoderInactivityTime > SETTING_MAX_INACTIVITY_TIME) {
João Lino's avatar
João Lino committed
1921
    if (digitalRead(ROTARY_ENCODER_SW_PIN)) {
1922 1923 1924 1925 1926 1927 1928 1929 1930 1931
      while (digitalRead(ROTARY_ENCODER_SW_PIN)) {
        delay(ROTARY_ENCODER_SW_DEBOUNCE_TIME);
      }

      now = millis();
      rotaryEncoderInactivityTime = now - lastInterruptTime;
      rotarySwDetectTime = now;

      repaint = true;
      refresh = true;
João Lino's avatar
João Lino committed
1932 1933
    }
  }
1934

João Lino's avatar
João Lino committed
1935 1936 1937 1938
  unsigned long switchInactivityTime = now - rotarySwDetectTime;
  return rotaryEncoderInactivityTime > switchInactivityTime ? switchInactivityTime : rotaryEncoderInactivityTime ;
}

1939
// ###################### Set Variables ##################################################
1940

João Lino's avatar
Rel.3  
João Lino committed
1941
void xWaitForAction(String title, String message) {
1942
  while (true) {
João Lino's avatar
Rel.3  
João Lino committed
1943 1944 1945
    // Check if pushbutton is pressed
    if ( digitalRead(ROTARY_ENCODER_SW_PIN) ) {
      // Wait until switch is released
1946 1947
      while ( digitalRead(ROTARY_ENCODER_SW_PIN) ) {}

João Lino's avatar
Rel.3  
João Lino committed
1948 1949 1950 1951 1952 1953 1954 1955 1956
      // debounce
      delay( 10 );

      // Job is done, break the circle
      break;
    } else {
      sing(BUZZ_1, PIEZO_PIN);

      // Print the message
1957
      if (! lcdPrint(&lcd, title, message)) {
João Lino's avatar
Rel.3  
João Lino committed
1958 1959
        break;
      }
1960 1961 1962 1963
    }
  }
}

João Lino's avatar
Rel.3  
João Lino committed
1964 1965 1966 1967 1968 1969 1970
boolean gotButtonPress(int iPin) {
  boolean ret = false;

  if ((digitalRead(iPin))) {    // check if pushbutton is pressed
    ret = true;
    while (digitalRead(iPin)) {}    // wait til switch is released
    delay(10);                            // debounce
1971
  }
1972

João Lino's avatar
Rel.3  
João Lino committed
1973 1974
  return ret;
}