Permalink
Browse files

Re-work scripting to work with new recipe language

  • Loading branch information...
1 parent 85122d4 commit 026c62ffb9d804e3088553f3a7fa08fd0ebbf59e @paulbaumgart committed Nov 29, 2010
Showing with 378 additions and 344 deletions.
  1. +186 −57 MLCScript.cpp
  2. +47 −25 MLCScript.h
  3. +1 −0 Util.h
  4. +2 −0 interface/Recipe.py
  5. +1 −1 interface/RecipeLexer.py
  6. +1 −0 interface/RecipeParser.py
  7. +16 −18 interface/SerialCommunicator.py
  8. +0 −6 interface/altbier.recipe
  9. +14 −0 interface/sample.recipe
  10. +110 −237 mash-lauter-control.cpp
View
@@ -1,89 +1,218 @@
#include "MLCScript.h"
#include "Util.h"
#define ASSUMED_HLT_VOLUME_ML 32000.0f
-#define MAX_TEMPERATURE 79.0f
+#define MAX_MASHING_TEMPERATURE 74.0f
+#define MAX_SPARGING_TEMPERATURE 79.0f
-MLCScript::MLCScript() {
- reset();
+static void readNextNullTerminatedString(char* outBuffer, uint8_t length)
+{
+ while (Serial.available() < length - 1) {}
+
+ uint8_t i;
+
+ for (i = 0; i < length - 1; i++)
+ outBuffer[i] = Serial.read();
+
+ outBuffer[i] = '\0';
}
-bool MLCScript::completed() {
- return activeSetpointIndex == -1;
+static void readNextFourBytes(char* outBuffer) {
+ while (Serial.available() < 4) {}
+
+ for (uint8_t i = 0; i < 4; i++)
+ outBuffer[i] = Serial.read();
}
-void MLCScript::reset() {
- counter = numSetpoints = activeSetpointIndex = mashWaterVolume = 0;
- maxIndex = -1;
- initialRampUpTemperature = NAN;
- initialRampUpCompleted = false;
+static void writeSuccess(void) {
+ Serial.println("OK");
}
-void MLCScript::addSetpoint(float temperature, uint32_t durationMillis) {
- maxIndex += 1;
+MLCScript::MLCScript(void (*pauseCallback)())
+ : m_pauseCallback (pauseCallback)
+{
+ reset();
+}
- if (maxIndex < NUM_SETPOINTS) {
- setpoints[maxIndex] = temperature;
- setpointDurations[maxIndex] = durationMillis;
- }
+void MLCScript::writeUnknownCommand(char* command) {
+ char msg[21] = "Unknown command: XXX";
+ msg[17] = command[0];
+ msg[18] = command[1];
+ msg[19] = command[2];
+ return writeFailure(msg);
}
-void MLCScript::setMashWaterVolume(uint32_t mashWaterMilliLiters) {
- mashWaterVolume = mashWaterMilliLiters;
+void MLCScript::writeFailure(char* msg) {
+ Serial.print("ERROR: ");
+ Serial.println(msg);
+ Serial.flush();
+ m_numStatements = 0;
+ m_completed = true;
+}
+
+void MLCScript::reset() {
+ m_counter = m_numStatements =
+ m_activeStatementIndex = m_mashWaterVolume = 0;
+ m_currentTemperatureTarget = NAN;
+ m_completed = false;
}
-void MLCScript::setMashWaterTemperature(float mashWaterCelsius) {
- mashWaterTemperature = mashWaterCelsius;
+void MLCScript::step(uint32_t elapsedMillis, float temperature1, float temperature2)
+{
+ if (m_activeStatementIndex >= m_numStatements) {
+ m_completed = true;
+ return;
+ }
+
+ ScriptStatement* currentStatement = &m_statements[m_activeStatementIndex];
+ uint32_t command = currentStatement->command.uint;
+
+ if (command == STRUINT("MSH")) {
+ m_mode = MASHING;
+ m_activeStatementIndex++;
+ step(elapsedMillis, temperature1, temperature2);
+ }
+ else if (command == STRUINT("SPG")) {
+ m_mode = SPARGING;
+ m_activeStatementIndex++;
+ step(elapsedMillis, temperature1, temperature2);
+ }
+ else if (command == STRUINT("PAU")) {
+ m_pauseCallback();
+ m_activeStatementIndex++;
+ }
+ else if (command == STRUINT("MWV")) {
+ m_mashWaterVolume = currentStatement->f1.volume;
+ m_activeStatementIndex++;
+ step(elapsedMillis, temperature1, temperature2);
+ }
+ else if (command == STRUINT("HEA")) {
+ float setpoint = currentTemperatureSetpoint();
+ if (m_mode == MASHING) {
+ setCurrentTemperatureTarget(setpoint +
+ (m_mashWaterVolume / ASSUMED_HLT_VOLUME_ML *
+ (setpoint - temperature2)));
+ if (temperature2 >= currentStatement->f1.temperature)
+ m_activeStatementIndex++;
+ }
+ else if (m_mode == SPARGING) {
+ setCurrentTemperatureTarget(setpoint);
+ if (temperature1 >= currentTemperatureTarget())
+ m_activeStatementIndex++;
+ }
+ }
+ else if (command == STRUINT("HLD")) {
+ m_counter += elapsedMillis;
+ setCurrentTemperatureTarget(currentStatement->f1.temperature);
+
+ if (m_counter >= currentStatement->f2.time) {
+ m_counter = 0;
+ m_activeStatementIndex++;
+ }
+ }
+ else
+ return writeUnknownCommand(currentStatement->command.str);
}
-bool MLCScript::inInitialRampUp(void) {
- return !initialRampUpCompleted && mashWaterVolume > 0 && !ISNAN(initialRampUpTemperature);
+bool MLCScript::completed()
+{
+ return m_completed;
}
-void MLCScript::step(uint32_t elapsedMillis, float currentTemperature) {
- if (!initialRampUpCompleted && mashWaterVolume > 0) {
- float setpoint = setpoints[activeSetpointIndex];
- initialRampUpTemperature = setpoint +
- (mashWaterVolume / ASSUMED_HLT_VOLUME_ML *
- (setpoint - mashWaterTemperature));
- if (initialRampUpTemperature > MAX_TEMPERATURE)
- initialRampUpTemperature = MAX_TEMPERATURE;
+Mode MLCScript::mode()
+{
+ return m_mode;
+}
- if (currentTemperature >= initialRampUpTemperature)
- initialRampUpCompleted = true;
- else
- return;
- }
- else if (maxIndex >= 0 && activeSetpointIndex >= 0) {
- counter += elapsedMillis;
+void MLCScript::readFromSerial()
+{
+ reset();
+ ScriptStatement currentStatement;
+ for (uint8_t i = 0; i < NUM_STATEMENTS; i++) {
+ readNextNullTerminatedString(currentStatement.command.str, 4);
+ uint32_t command = currentStatement.command.uint;
+ if (command == STRUINT("MSH") ||
+ command == STRUINT("SPG") ||
+ command == STRUINT("PAU")) {
+ currentStatement.f1.temperature = NAN;
+ writeSuccess();
+ }
+ else if (command == STRUINT("MWV") ||
+ command == STRUINT("HEA")) {
+ writeSuccess();
+ readNextFourBytes((char*)&currentStatement.f1);
+ writeSuccess();
+ }
+ else if (command == STRUINT("HLD")) {
+ writeSuccess();
+ readNextFourBytes((char*)&currentStatement.f1);
+ writeSuccess();
+ readNextFourBytes((char*)&currentStatement.f2);
+ writeSuccess();
+ }
+ else if (command == STRUINT("END"))
+ return writeSuccess();
+ else
+ return writeUnknownCommand(currentStatement.command.str);
+
+ m_statements[m_numStatements] = currentStatement;
+ m_numStatements++;
+ }
+
+ readNextNullTerminatedString(currentStatement.command.str, 4);
+ if (currentStatement.command.uint != STRUINT("END"))
+ return writeFailure((char*)"Too many statements in script.");
+ else
+ return writeSuccess();
+}
- if (counter > setpointDurations[activeSetpointIndex]) {
- // this duration has ended
- counter = 0;
- activeSetpointIndex += 1;
+void MLCScript::setCurrentTemperatureTarget(float currentTemperatureTarget)
+{
+ if (m_mode == MASHING) {
+ if (currentTemperatureTarget > MAX_MASHING_TEMPERATURE)
+ currentTemperatureTarget = MAX_MASHING_TEMPERATURE;
+ }
+ else if (m_mode == SPARGING) {
+ if (currentTemperatureTarget > MAX_SPARGING_TEMPERATURE)
+ currentTemperatureTarget = MAX_SPARGING_TEMPERATURE;
+ }
+
+ m_currentTemperatureTarget = currentTemperatureTarget;
+}
- if (activeSetpointIndex > maxIndex)
- activeSetpointIndex = -1;
- }
- }
+float MLCScript::currentTemperatureSetpoint(void)
+{
+ return m_statements[m_activeStatementIndex].f1.temperature;
}
-float MLCScript::currentTemperatureSetpoint(void) {
- if (!initialRampUpCompleted)
- return initialRampUpTemperature;
- else if (activeSetpointIndex >= 0)
- return setpoints[activeSetpointIndex];
- else
- return NAN;
+float MLCScript::currentTemperatureTarget(void)
+{
+ return m_currentTemperatureTarget;
}
-uint32_t MLCScript::timeInCurrentInterval(void) {
- return counter;
+uint32_t MLCScript::timeInCurrentInterval(void)
+{
+ return m_counter;
}
-uint32_t MLCScript::currentIntervalDuration(void) {
- if (activeSetpointIndex >= 0)
- return setpointDurations[activeSetpointIndex];
+uint32_t MLCScript::currentIntervalDuration(void)
+{
+ ScriptStatement* currentStatement = &m_statements[m_activeStatementIndex];
+
+ if (currentStatement->command.uint == STRUINT("HLD"))
+ return currentStatement->f2.time;
else
return 0;
}
+void MLCScript::currentCommand(char* outBuffer) {
+ char defaultCommand[] = "NON";
+ char* command;
+ if (m_numStatements > 0)
+ command = m_statements[m_activeStatementIndex].command.str;
+ else
+ command = defaultCommand;
+
+ for (int i = 0; i < 4; i++)
+ outBuffer[i] = command[i];
+}
+
View
@@ -3,33 +3,55 @@
#include <WProgram.h>
-#define NUM_SETPOINTS 10
+#define NUM_STATEMENTS 32
+
+typedef struct {
+ union {
+ char str[4];
+ uint32_t uint;
+ } command;
+ union {
+ uint32_t volume;
+ float temperature;
+ } f1;
+ union {
+ uint32_t time;
+ } f2;
+} ScriptStatement;
+
+typedef enum Mode {
+ MASHING = 0,
+ SPARGING,
+ MODE_COUNT
+} Mode;
class MLCScript {
- public:
- MLCScript();
- bool completed(void);
- void reset(void);
- void addSetpoint(float temperature, uint32_t durationMillis);
- void setMashWaterVolume(uint32_t mashWaterMilliLiters);
- void setMashWaterTemperature(float mashWaterCelsius);
- bool inInitialRampUp(void);
- void step(uint32_t elapsedMillis, float currentTemperature);
- float currentTemperatureSetpoint(void);
- uint32_t timeInCurrentInterval(void);
- uint32_t currentIntervalDuration(void);
-
- private:
- uint32_t counter,
- setpointDurations[NUM_SETPOINTS],
- mashWaterVolume;
- float setpoints[NUM_SETPOINTS],
- initialRampUpTemperature,
- mashWaterTemperature;
- uint8_t numSetpoints;
- int8_t activeSetpointIndex,
- maxIndex;
- bool initialRampUpCompleted;
+public:
+ MLCScript(void (*pauseCallback)());
+ void reset(void);
+ void step(uint32_t elapsedMillis, float temperature1, float temperature2);
+ Mode mode(void);
+ void readFromSerial(void);
+ float currentTemperatureSetpoint(void);
+ float currentTemperatureTarget(void);
+ uint32_t timeInCurrentInterval(void);
+ uint32_t currentIntervalDuration(void);
+ bool completed(void);
+ void currentCommand(char* outBuffer);
+
+private:
+ void setCurrentTemperatureTarget(float);
+ void writeFailure(char*);
+ void writeUnknownCommand(char*);
+ enum Mode m_mode;
+ uint32_t m_counter,
+ m_mashWaterVolume;
+ ScriptStatement m_statements[NUM_STATEMENTS];
+ uint8_t m_numStatements;
+ float m_currentTemperatureTarget;
+ int8_t m_activeStatementIndex;
+ bool m_completed;
+ void (*m_pauseCallback)();
};
#endif
View
1 Util.h
@@ -1,2 +1,3 @@
#define ISNAN(x) ((x) != (x))
+#define STRUINT(x) (*(uint32_t*)(x))
View
@@ -34,6 +34,8 @@ def human_readable(self):
output.append("\tHOLD AT: %s C FOR: %s seconds" %
(struct.unpack('f', temperature)[0],
float(struct.unpack('L', time)[0]) / 1000))
+ elif command == 'END':
+ pass
else:
raise ValueError, command
View
@@ -2,9 +2,9 @@
class RecipeLexer(object):
TOKENS = [
+ (r'(mash )?(water )?vol(\.|ume)?:?', 'MASH_VOLUME'),
(r'mash(ing)?:?', 'MASHING'),
(r'sparg(e|ing):?', 'SPARGING'),
- (r'(mash )?(water )?vol(\.|ume)?:?', 'MASH_VOLUME'),
(r'heat( to)?:?', 'HEAT'),
(r'hold( at)?:?', 'HOLD'),
(r'wait|pause', 'PAUSE'),
@@ -27,6 +27,7 @@ def parse(self):
result.extend(next_statement)
else:
self.__fail()
+ result.append('END')
return result
def __fail(self):
Oops, something went wrong.

0 comments on commit 026c62f

Please sign in to comment.