diff --git a/lambda-test/rules-test.c b/lambda-test/rules-test.c index d3a7d54..e12da95 100644 --- a/lambda-test/rules-test.c +++ b/lambda-test/rules-test.c @@ -40,7 +40,18 @@ reason(meas); assertFalse(rules[0].fired); + resetRules(); + dir = burning; + reason(meas); + assertFalse(rules[0].fired); + + resetRules(); + dir = warm_start; + reason(meas); + assertFalse(rules[0].fired); + meas.tempI = 500; + meas.lambda = 1500; resetRules(); dir = burning_down; @@ -58,6 +69,18 @@ assertTrue(rules[0].fired); assertTrue(50 == airgate); + resetRules(); + dir = burning; + reason(meas); + assertTrue(rules[0].fired); + assertTrue(50 == airgate); + + resetRules(); + dir = warm_start; + reason(meas); + assertTrue(rules[0].fired); + assertTrue(50 == airgate); + cancelAlert(false); return true; @@ -82,7 +105,18 @@ reason(meas); assertFalse(rules[1].fired); + resetRules(); + dir = burning; + reason(meas); + assertFalse(rules[1].fired); + + resetRules(); + dir = warm_start; + reason(meas); + assertFalse(rules[1].fired); + meas.tempI = 699; + meas.lambda = 1500; resetRules(); dir = firing_up; @@ -95,6 +129,16 @@ assertFalse(rules[1].fired); resetRules(); + dir = burning; + reason(meas); + assertFalse(rules[1].fired); + + resetRules(); + dir = warm_start; + reason(meas); + assertFalse(rules[1].fired); + + resetRules(); dir = burning_down; reason(meas); assertTrue(rules[1].fired); @@ -124,7 +168,18 @@ reason(meas); assertFalse(rules[2].fired); + resetRules(); + dir = burning; + reason(meas); + assertFalse(rules[2].fired); + + resetRules(); + dir = warm_start; + reason(meas); + assertFalse(rules[2].fired); + meas.tempI = 399; + meas.lambda = 1500; resetRules(); dir = firing_up; @@ -137,6 +192,16 @@ assertFalse(rules[2].fired); resetRules(); + dir = burning; + reason(meas); + assertFalse(rules[2].fired); + + resetRules(); + dir = warm_start; + reason(meas); + assertFalse(rules[2].fired); + + resetRules(); dir = burning_down; reason(meas); assertTrue(rules[2].fired); @@ -188,7 +253,7 @@ assertTrue(rules[3].fired); assertTrue(100 == airgate); - meas.lambda = 1300; + meas.lambda = 1400; age = 0; reason(meas); assertFalse(rules[3].fired); @@ -206,7 +271,7 @@ setHeaterState(heaterStateReady); meas.tempI = 500; - meas.lambda = 1601; + meas.lambda = 1501; resetRules(); reason(meas); assertFalse(rules[4].fired); @@ -218,7 +283,7 @@ assertFalse(rules[4].fired); meas.tempI = 501; - meas.lambda = 1601; + meas.lambda = 1501; resetRules(); airgate = 50; reason(meas); @@ -226,14 +291,14 @@ assertTrue(50 == airgate); meas.tempI = 501; - meas.lambda = 1601; + meas.lambda = 1501; resetRules(); airgate = 100; reason(meas); assertTrue(rules[4].fired); assertTrue(50 == airgate); - meas.lambda = 1500; + meas.lambda = 1400; age = 0; reason(meas); assertFalse(rules[4].fired); @@ -404,32 +469,26 @@ reason(meas); assertTrue(dir == firing_up); - meas.tempI = 690; + meas.tempI = 699; meas.lambda = 2000; age = 180; reason(meas); assertTrue(dir == firing_up); - meas.tempI = 690; + meas.tempI = 699; meas.lambda = 2000; age = 180; reason(meas); assertTrue(dir == none); - meas.tempI = 690; - meas.lambda = 1900; - age = 180; - reason(meas); - assertTrue(dir == burning); - meas.tempI = 700; - meas.lambda = 2000; + meas.lambda = 1899; age = 180; reason(meas); assertTrue(dir == burning); - meas.tempI = 800; - meas.lambda = 1999; + meas.tempI = 701; + meas.lambda = 1900; age = 180; reason(meas); assertTrue(dir == burning); @@ -448,29 +507,23 @@ reason(meas); assertTrue(dir == none); - meas.tempI = 900; - meas.lambda = 1999; - age = 180; - reason(meas); - assertTrue(dir == burning); - meas.tempI = 800; - meas.lambda = 1999; + meas.lambda = 1899; age = 180; reason(meas); assertTrue(dir == burning); - meas.tempI = 750; - meas.lambda = 1999; + meas.tempI = 700; + meas.lambda = 2000; age = 180; reason(meas); assertTrue(dir == burning); meas.tempI = 699; - meas.lambda = 2000; + meas.lambda = 1899; age = 180; reason(meas); - assertTrue(dir == burning_down); + assertTrue(dir == burning); meas.tempI = 699; meas.lambda = 2000; @@ -489,7 +542,39 @@ return true; } -// TODO add tests for "burning" and "warm start" +static bool testReasonDirWarmStart(void) { + + resetRules(); + Measurement meas = {999, 0, 1999}; + + age = 0; + reason(meas); + assertTrue(dir == none); + + meas.tempI = 699; + meas.lambda = 2000; + age = 180; + reason(meas); + assertTrue(dir == burning_down); + + meas.tempI = 100; + meas.lambda = 2000; + age = 180; + reason(meas); + assertTrue(dir == burning_down); + + meas.tempI = 120; + meas.lambda = 2000; + age = 180; + reason(meas); + assertTrue(dir == warm_start); + assertTrue(heaterStateUp == getHeaterState()); + assertTrue(airgate == 100); + + cancelAlert(false); + + return true; +} /* Test "class" */ static const char class[] PROGMEM = "rules"; @@ -508,6 +593,7 @@ static const char testHeaterTimeout_P[] PROGMEM = "testHeaterTimeout"; static const char testReasonDirBurnUp_P[] PROGMEM = "testReasonDirBurnUp"; static const char testReasonDirBurnDown_P[] PROGMEM = "testReasonDirBurnDown"; +static const char testReasonDirWarmStart_P[] PROGMEM = "testReasonDirWarmStart"; /* Tests */ static TestCase const tests[] = { @@ -523,7 +609,8 @@ {class, testHeaterFaultNoheat_P, testHeaterFaultNoheat}, {class, testHeaterTimeout_P, testHeaterTimeout}, {class, testReasonDirBurnUp_P, testReasonDirBurnUp}, - {class, testReasonDirBurnDown_P, testReasonDirBurnDown} + {class, testReasonDirBurnDown_P, testReasonDirBurnDown}, + {class, testReasonDirWarmStart_P, testReasonDirWarmStart} }; TestClass rulesClass = {tests, sizeof(tests) / sizeof(tests[0])}; diff --git a/lambda/TODO b/lambda/TODO index 135e3c1..8a62f5b 100644 --- a/lambda/TODO +++ b/lambda/TODO @@ -11,7 +11,7 @@ - AVCC should be connected to VCC via an LC network * Release/put in Makefile? -- Makefile: LANG = 0 -- pins.h LCD pins +- Makefile: LANG = 0 (1) +- pins.h LCD pins (prototype) - interrupts.h TIMER0_COMP_MATCH 122/244 (124/248) - sensors.h: SHUNT_MILLIOHMS 100 (111) \ No newline at end of file diff --git a/lambda/rules.c b/lambda/rules.c index 26f47b2..23bd95a 100644 --- a/lambda/rules.c +++ b/lambda/rules.c @@ -27,8 +27,9 @@ */ static void airgate50(bool* const fired, int8_t const dir, Measurement const meas) { - if (! *fired && dir == firing_up && - meas.tempI >= TEMP_AIRGATE_50) { + if (! *fired && (dir == firing_up || dir == burning || dir == warm_start) && + meas.tempI >= TEMP_AIRGATE_50 && meas.lambda >= LAMBDA_TOO_LEAN && + airgate > 50) { airgate = 50; alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_50_0), PSTR(""), false); *fired = true; @@ -41,8 +42,8 @@ */ static void airgate25(bool* const fired, int8_t const dir, Measurement const meas) { - if (! *fired && dir == burning_down && - meas.tempI < TEMP_AIRGATE_25) { + if (! *fired && dir == burning_down && meas.tempI < TEMP_AIRGATE_25 && + meas.lambda >= LAMBDA_TOO_LEAN && airgate > 25) { airgate = 25; alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_AIRGATE_25_0), PSTR(""), false); *fired = true; @@ -55,8 +56,8 @@ */ static void airgateClose(bool* const fired, int8_t const dir, Measurement const meas) { - if (! *fired && dir == burning_down && - meas.tempI < TEMP_AIRGATE_0) { + if (! *fired && dir == burning_down && meas.tempI < TEMP_AIRGATE_0 && + meas.lambda >= LAMBDA_TOO_LEAN && airgate > 0) { setHeaterOn(false); airgate = 0; alert_P(BEEPS, LENGTH, TONE, @@ -163,8 +164,10 @@ setHeaterOn(false); alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_FIRE_OUT_0), PSTR(""), false); } - if (heaterUptime >= 3600 && meas.tempI < TEMP_AIRGATE_0) { + if (heaterUptime >= 10800 && meas.tempI < TEMP_AIRGATE_0) { setHeaterOn(false); + alert_P(3, 5, TONE, PSTR(MSG_HEATER_OFF_0), + PSTR(MSG_HEATER_OFF_1), false); } } @@ -230,12 +233,16 @@ dir = burning; } if ((rulesMeasPrev.tempI - meas.tempI) >= TEMP_DELTA_DOWN && - rulesMeasMax.tempI >= TEMP_MIN && meas.lambda >= LAMBDA_MAX) { + meas.tempI < TEMP_MIN && rulesMeasMax.tempI >= TEMP_MIN && + meas.lambda >= LAMBDA_MAX) { dir = burning_down; } if ((meas.tempI - rulesMeasPrev.tempI) >= TEMP_DELTA_UP && meas.tempI < TEMP_MIN && rulesMeasMax.tempI >= TEMP_MIN) { - // it seems wood has been added - reset some measurements and rules + // it seems wood has been added or - probably more likely - oven + // was fired up without resetting. Should probably work that way + // anyway, making manual reset unnecessary? + // TODO make a complete reset including time? dir = warm_start; rulesMeasMax.tempI = meas.tempI; size_t rulesSize = sizeof(rules) / sizeof(rules[0]); @@ -245,6 +252,7 @@ if (! isHeaterOn() && getHeaterState() != heaterStateFault) { setHeaterOn(true); } + airgate = 100; } rulesMeasPrev = meas; diff --git a/lambda/rules.h b/lambda/rules.h index c191407..50026fa 100644 --- a/lambda/rules.h +++ b/lambda/rules.h @@ -11,13 +11,13 @@ #include #include "sensors.h" -#define BEEPS 30 +#define BEEPS 20 #define LENGTH 10 #define TONE 31 /** Age of previous measurements to compare against */ #define AGE_MEAS_PREV 180 -/** Oven reaches at least this temperature when the fire is burning */ +/** Exhaust reaches at least this temperature when the fire is burning */ #define TEMP_MIN 700 /** Min. increase in temperature during AGE_MEAS_PREV when firing up */ #define TEMP_DELTA_UP 10 @@ -36,16 +36,16 @@ #define TEMP_FIRE_OUT 100 /** Min. temperature at which to consider the fire to fire up again */ #define TEMP_FIRE_OUT_RESET 125 -/** Fire is considered burning if lambda is below this value */ -#define LAMBDA_MAX 2000 +/** Fire is considered fully burning if lambda is below this value */ +#define LAMBDA_MAX 1900 /** Combustion is considered too rich if lambda is below this value */ #define LAMBDA_TOO_RICH 1200 /** Combustion is considered lean enough again if lambda is above this value */ -#define LAMBDA_TOO_RICH_RESET 1300 +#define LAMBDA_TOO_RICH_RESET 1400 /** Combustion is considered too lean if lambda is above this value */ -#define LAMBDA_TOO_LEAN 1600 +#define LAMBDA_TOO_LEAN 1500 /** Combustion is considered rich enough again if lambda is below this value */ -#define LAMBDA_TOO_LEAN_RESET 1500 +#define LAMBDA_TOO_LEAN_RESET 1400 typedef enum { none = 0,