diff --git a/lambda-test/airgate-test.c b/lambda-test/airgate-test.c index fafe36a..db4f9b9 100644 --- a/lambda-test/airgate-test.c +++ b/lambda-test/airgate-test.c @@ -17,6 +17,7 @@ static bool testSetAirgate(void) { + setDriverFault(false); resetAirgate(0); setAirgate(100); @@ -45,10 +46,10 @@ static bool testMakeSteps(void) { - const uint16_t SPEED_PROD = (uint16_t)MIN_SPEED * MAX_SPEED; const uint16_t ramp = MIN(abs(MAX_SPEED - MIN_SPEED), (100 << STEPPING_MODE) >> 1); uint8_t speed = MIN_SPEED; + setDriverFault(false); resetAirgate(0); setAirgate(100); @@ -111,6 +112,32 @@ return true; } +static bool testIsDriverFault(void) { + + setDriverFault(true); + + assertTrue(isDriverFault()); + + setDriverFault(false); + + assertFalse(isDriverFault()); + + return true; +} + +static bool testRememberAirgate(void) { + + resetAirgate(0); + setAirgate(100); + + resetAirgate(0); + initAirgate(); + + assertTrue(100 == getAirgate()); + + return true; +} + /* Test "class" */ static const char class[] PROGMEM = "airgate"; @@ -118,12 +145,16 @@ static const char testSetAirgate_P[] PROGMEM = "testSetAirgate"; static const char testMakeSteps_P[] PROGMEM = "testMakeSteps"; static const char testSetSleepMode_P[] PROGMEM = "testSetSleepMode"; +static const char testIsDriverFault_P[] PROGMEM = "testIsDriverFault"; +static const char testRememberAirgate_P[] PROGMEM = "testRememberAirgate"; /* Tests */ static TestCase const tests[] = { {class, testSetAirgate_P, testSetAirgate}, {class, testMakeSteps_P, testMakeSteps}, - {class, testSetSleepMode_P, testSetSleepMode} + {class, testSetSleepMode_P, testSetSleepMode}, + {class, testIsDriverFault_P, testIsDriverFault}, + {class, testRememberAirgate_P, testRememberAirgate} }; TestClass airgateClass = {tests, ARRAY_LENGTH(tests)}; diff --git a/lambda-test/alert-test.c b/lambda-test/alert-test.c index d2d9291..2ac36a7 100644 --- a/lambda-test/alert-test.c +++ b/lambda-test/alert-test.c @@ -18,14 +18,14 @@ extern uint16_t beepLength; extern uint8_t oscCount; -static bool testOscillateBeep(void) { +static bool testMakeBeeps(void) { beepCount = 0; oscCount = 0; // alert with two beeps with a length of 2 and tone 31 alert(2, 2, 31, "a", "b", false); - oscillateBeep(); - oscillateBeep(); + makeBeeps(); + makeBeeps(); // beep on, alertActive true assertTrue(beepCount == 2); @@ -34,8 +34,8 @@ assertTrue(bit_is_set(TCCR1A, COM1A0)); assertTrue(isAlertActive()); - oscillateBeep(); - oscillateBeep(); + makeBeeps(); + makeBeeps(); // beep off, alertActive still true assertTrue(beepCount == 1); @@ -43,8 +43,8 @@ assertTrue(bit_is_clear(TCCR1A, COM1A0)); assertTrue(isAlertActive()); - oscillateBeep(); - oscillateBeep(); + makeBeeps(); + makeBeeps(); // beep on, alertActive still true assertTrue(beepCount == 1); @@ -52,8 +52,8 @@ assertTrue(bit_is_set(TCCR1A, COM1A0)); assertTrue(isAlertActive()); - oscillateBeep(); - oscillateBeep(); + makeBeeps(); + makeBeeps(); // beep off, alertActive false assertTrue(beepCount == 0); @@ -122,14 +122,14 @@ static const char class[] PROGMEM = "alert"; /* Test names */ -static const char testOscillateBeep_P[] PROGMEM = "testOscillateBeep"; +static const char testMakeBeeps_P[] PROGMEM = "testMakeBeeps"; static const char testBeep_P[] PROGMEM = "testBeep"; static const char testAlert_P[] PROGMEM = "testAlert"; static const char testCancelAlert_P[] PROGMEM = "testCancelAlert"; /* Tests */ static TestCase const tests[] = { - {class, testOscillateBeep_P, testOscillateBeep}, + {class, testMakeBeeps_P, testMakeBeeps}, {class, testBeep_P, testBeep}, {class, testAlert_P, testAlert}, {class, testCancelAlert_P, testCancelAlert} diff --git a/lambda-test/rules-test.c b/lambda-test/rules-test.c index fab9aa8..fff8a6f 100644 --- a/lambda-test/rules-test.c +++ b/lambda-test/rules-test.c @@ -20,29 +20,31 @@ extern uint8_t measCount; extern int8_t state; -extern Rule rules[]; +extern Rule fastRules[]; +extern Rule slowRules[]; static bool testAirgate50(void) { + setDriverFault(false); Measurement meas = {0, 0, 0, 0}; resetRules(true); resetAirgate(AIRGATE_OPEN); state = burning_down; reason(meas); - assertFalse(rules[0].fired); + assertFalse(slowRules[0].fired); resetRules(true); resetAirgate(AIRGATE_OPEN); state = undefined; reason(meas); - assertFalse(rules[0].fired); + assertFalse(slowRules[0].fired); resetRules(true); resetAirgate(AIRGATE_OPEN); state = firing_up; reason(meas); - assertFalse(rules[0].fired); + assertFalse(slowRules[0].fired); meas.tempI = TEMP_AIRGATE_50; meas.lambda = LAMBDA_TOO_LEAN; @@ -51,20 +53,20 @@ resetAirgate(AIRGATE_OPEN); state = burning_down; reason(meas); - assertFalse(rules[0].fired); + assertFalse(slowRules[0].fired); resetRules(true); resetAirgate(AIRGATE_OPEN); state = undefined; reason(meas); - assertFalse(rules[0].fired); + assertFalse(slowRules[0].fired); resetRules(true); resetAirgate(AIRGATE_50); state = firing_up; reason(meas); stepUntilDone(); - assertFalse(rules[0].fired); + assertFalse(slowRules[0].fired); assertTrue(AIRGATE_50 == getAirgate()); resetRules(true); @@ -72,7 +74,7 @@ state = firing_up; reason(meas); stepUntilDone(); - assertTrue(rules[0].fired); + assertTrue(slowRules[0].fired); assertTrue(AIRGATE_50 == getAirgate()); cancelAlert(); @@ -82,25 +84,26 @@ static bool testAirgate25(void) { + setDriverFault(false); Measurement meas = {999, 0, 0, 0}; resetRules(true); resetAirgate(AIRGATE_OPEN); state = firing_up; reason(meas); - assertFalse(rules[1].fired); + assertFalse(slowRules[1].fired); resetRules(true); resetAirgate(AIRGATE_OPEN); state = undefined; reason(meas); - assertFalse(rules[1].fired); + assertFalse(slowRules[1].fired); resetRules(true); resetAirgate(AIRGATE_OPEN); state = burning_down; reason(meas); - assertFalse(rules[1].fired); + assertFalse(slowRules[1].fired); meas.tempI = TEMP_AIRGATE_25 - 1; meas.lambda = LAMBDA_TOO_LEAN; @@ -109,20 +112,20 @@ resetAirgate(AIRGATE_OPEN); state = firing_up; reason(meas); - assertFalse(rules[1].fired); + assertFalse(slowRules[1].fired); resetRules(true); resetAirgate(AIRGATE_OPEN); state = undefined; reason(meas); - assertFalse(rules[1].fired); + assertFalse(slowRules[1].fired); resetRules(true); resetAirgate(AIRGATE_25); state = burning_down; reason(meas); stepUntilDone(); - assertFalse(rules[1].fired); + assertFalse(slowRules[1].fired); assertTrue(AIRGATE_25 == getAirgate()); resetRules(true); @@ -130,7 +133,7 @@ state = burning_down; reason(meas); stepUntilDone(); - assertTrue(rules[1].fired); + assertTrue(slowRules[1].fired); assertTrue(AIRGATE_25 == getAirgate()); cancelAlert(); @@ -140,25 +143,26 @@ static bool testAirgateClose(void) { + setDriverFault(false); Measurement meas = {999, 0, 0, 0}; resetRules(true); resetAirgate(AIRGATE_OPEN); state = firing_up; reason(meas); - assertFalse(rules[2].fired); + assertFalse(slowRules[2].fired); resetRules(true); resetAirgate(AIRGATE_OPEN); state = undefined; reason(meas); - assertFalse(rules[2].fired); + assertFalse(slowRules[2].fired); resetRules(true); resetAirgate(AIRGATE_OPEN); state = burning_down; reason(meas); - assertFalse(rules[2].fired); + assertFalse(slowRules[2].fired); meas.tempI = TEMP_AIRGATE_0 - 1; meas.lambda = LAMBDA_MAX; @@ -167,20 +171,20 @@ resetAirgate(AIRGATE_OPEN); state = firing_up; reason(meas); - assertFalse(rules[2].fired); + assertFalse(slowRules[2].fired); resetRules(true); resetAirgate(AIRGATE_OPEN); state = undefined; reason(meas); - assertFalse(rules[2].fired); + assertFalse(slowRules[2].fired); resetRules(true); resetAirgate(AIRGATE_CLOSE); state = burning_down; reason(meas); stepUntilDone(); - assertFalse(rules[2].fired); + assertFalse(slowRules[2].fired); assertTrue(AIRGATE_CLOSE == getAirgate()); // airgate25 kicks in first and prevents airgateClose from running @@ -190,7 +194,7 @@ state = burning_down; reason(meas); stepUntilDone(); - assertFalse(rules[2].fired); + assertFalse(slowRules[2].fired); assertFalse(AIRGATE_CLOSE == getAirgate()); // now airgateClose kicks in @@ -198,7 +202,7 @@ state = burning_down; reason(meas); stepUntilDone(); - assertTrue(rules[2].fired); + assertTrue(slowRules[2].fired); assertTrue(AIRGATE_CLOSE == getAirgate()); cancelAlert(); @@ -208,6 +212,7 @@ static bool testTooRich(void) { + setDriverFault(false); Measurement meas = {0, 0, 0, 1000}; setHeaterState(heaterStateOn); @@ -217,21 +222,21 @@ resetRules(true); resetAirgate(AIRGATE_OPEN); reason(meas); - assertFalse(rules[3].fired); + assertFalse(slowRules[3].fired); meas.tempI = TEMP_FIRE_OUT + 1; meas.lambda = LAMBDA_MAX; resetRules(true); resetAirgate(AIRGATE_OPEN); reason(meas); - assertFalse(rules[3].fired); + assertFalse(slowRules[3].fired); meas.tempI = TEMP_FIRE_OUT; meas.lambda = LAMBDA_TOO_RICH - 1; resetRules(true); resetAirgate(AIRGATE_OPEN); reason(meas); - assertFalse(rules[3].fired); + assertFalse(slowRules[3].fired); meas.tempI = TEMP_FIRE_OUT + 1; meas.lambda = LAMBDA_TOO_RICH - 1; @@ -239,7 +244,7 @@ resetAirgate(AIRGATE_50); reason(meas); stepUntilDone(); - assertFalse(rules[3].fired); + assertFalse(slowRules[3].fired); assertTrue(AIRGATE_50 == getAirgate()); meas.tempI = TEMP_FIRE_OUT + 1; @@ -248,7 +253,7 @@ resetAirgate(AIRGATE_25); reason(meas); stepUntilDone(); - assertTrue(rules[3].fired); + assertTrue(slowRules[3].fired); assertTrue(AIRGATE_50 == getAirgate()); cancelAlert(); @@ -258,6 +263,7 @@ static bool testTooLean(void) { + setDriverFault(false); Measurement meas = {0, 0, 0, 1000}; setHeaterState(heaterStateOn); @@ -267,14 +273,14 @@ resetRules(true); resetAirgate(AIRGATE_OPEN); reason(meas); - assertFalse(rules[4].fired); + assertFalse(slowRules[4].fired); meas.tempI = TEMP_AIRGATE_50 + 1; meas.lambda = 1300; resetRules(true); resetAirgate(AIRGATE_OPEN); reason(meas); - assertFalse(rules[4].fired); + assertFalse(slowRules[4].fired); meas.tempI = TEMP_AIRGATE_50 + 1; meas.lambda = LAMBDA_TOO_LEAN + 1; @@ -282,7 +288,7 @@ resetAirgate(AIRGATE_50); reason(meas); stepUntilDone(); - assertFalse(rules[4].fired); + assertFalse(slowRules[4].fired); assertTrue(AIRGATE_50 == getAirgate()); meas.tempI = TEMP_AIRGATE_50 + 1; @@ -291,7 +297,7 @@ resetAirgate(AIRGATE_OPEN); reason(meas); stepUntilDone(); - assertTrue(rules[4].fired); + assertTrue(slowRules[4].fired); assertTrue(AIRGATE_50 == getAirgate()); cancelAlert(); @@ -301,6 +307,7 @@ static bool testFireOut(void) { + setDriverFault(false); Measurement meas = {0, 0, 0, 0}; resetRules(true); @@ -310,27 +317,27 @@ meas.tempI = 50; measCount = 10; reason(meas); - assertFalse(rules[5].fired); + assertFalse(slowRules[5].fired); meas.tempI = TEMP_FIRE_OUT; measCount = 10; reason(meas); - assertFalse(rules[5].fired); + assertFalse(slowRules[5].fired); meas.tempI = TEMP_FIRE_OUT_RESET; measCount = 10; reason(meas); - assertFalse(rules[5].fired); + assertFalse(slowRules[5].fired); meas.tempI = TEMP_FIRE_OUT - 1; measCount = 10; reason(meas); - assertTrue(rules[5].fired); + assertTrue(slowRules[5].fired); meas.tempI = TEMP_FIRE_OUT_RESET; measCount = 10; reason(meas); - assertFalse(rules[5].fired); + assertFalse(slowRules[5].fired); cancelAlert(); @@ -339,28 +346,29 @@ static bool testWarmStart(void) { + setDriverFault(false); Measurement meas = {TEMP_AIRGATE_50, 0, 0, 0}; setHeaterState(heaterStateOff); resetRules(true); resetAirgate(AIRGATE_50); - rules[6].fired = false; + slowRules[6].fired = false; reason(meas); stepUntilDone(); assertTrue(AIRGATE_50 == getAirgate()); assertTrue(heaterStateOff == getHeaterState()); - assertFalse(rules[6].fired); + assertFalse(slowRules[6].fired); resetRules(true); resetAirgate(AIRGATE_50); - rules[6].fired = false; + slowRules[6].fired = false; state = firing_up; reason(meas); stepUntilDone(); assertTrue(AIRGATE_OPEN == getAirgate()); assertTrue(heaterStateOn == getHeaterState()); - assertTrue(rules[6].fired); + assertTrue(slowRules[6].fired); cancelAlert(); @@ -470,6 +478,27 @@ return true; } +static bool testDriverFault(void) { + + resetRules(true); + resetTime(); + Measurement meas = {0, 0, 0, 0}; + + setDriverFault(true); + reason(meas); + + assertTrue(fastRules[3].fired); + + setDriverFault(false); + reason(meas); + + assertFalse(fastRules[3].fired); + + cancelAlert(); + + return true; +} + /* Test "class" */ static const char class[] PROGMEM = "rules"; @@ -486,6 +515,7 @@ static const char testHeaterFaultShort_P[] PROGMEM = "testHeaterFaultShort"; static const char testHeaterFaultNoheat_P[] PROGMEM = "testHeaterFaultNoheat"; static const char testHeaterTimeout_P[] PROGMEM = "testHeaterTimeout"; +static const char testDriverFault_P[] PROGMEM = "testDriverFault"; /* Tests */ static TestCase const tests[] = { @@ -500,7 +530,8 @@ {class, testHeaterFaultNoconn_P, testHeaterFaultNoconn}, {class, testHeaterFaultShort_P, testHeaterFaultShort}, {class, testHeaterFaultNoheat_P, testHeaterFaultNoheat}, - {class, testHeaterTimeout_P, testHeaterTimeout} + {class, testHeaterTimeout_P, testHeaterTimeout}, + {class, testDriverFault_P, testDriverFault} }; TestClass rulesClass = {tests, ARRAY_LENGTH(tests)}; diff --git a/lambda-test/utils.c b/lambda-test/utils.c index fab2de0..f030185 100644 --- a/lambda-test/utils.c +++ b/lambda-test/utils.c @@ -7,6 +7,7 @@ #include "utils.h" #include "airgate.h" +#include "pins.h" void stepUntilDone(void) { while (isAirgateBusy()) { @@ -14,3 +15,13 @@ } makeSteps(); } + +void setDriverFault(bool const fault) { + if (fault) { + // disable pull-up resistor + PORT &= ~(1 << PIN_FAULT); + } else { + // enable pull-up resistor + PORT |= (1 << PIN_FAULT); + } +} diff --git a/lambda-test/utils.h b/lambda-test/utils.h index 31d2e22..f5992df 100644 --- a/lambda-test/utils.h +++ b/lambda-test/utils.h @@ -10,10 +10,17 @@ #ifndef UTILS_H_ #define UTILS_H_ +#include + /** * Trigger steps as done by the timer ISR until the requested motor position * is reached. */ void stepUntilDone(void); +/** + * Simulates fault or normal operation of the stepper motor driver. + */ +void setDriverFault(bool const fault); + #endif /* UTILS_H_ */ diff --git a/lambda/airgate.c b/lambda/airgate.c index c00a70a..b32d482 100644 --- a/lambda/airgate.c +++ b/lambda/airgate.c @@ -7,12 +7,15 @@ * Simple stepper motor control with a linear acceleration profile using the * DRV8825. An absolute position from 0 to 255 can be set where 200 units * correspond to 360° rotation (with 1.8° step angle). + * TODO limit switch for AIRGATE_CLOSE position */ #include #include #include +#include #include "airgate.h" +#include "eeprom.h" #include "integers.h" #include "interrupts.h" #include "pins.h" @@ -89,19 +92,23 @@ } } +void initAirgate(void) { + uint16_t val = eeprom_read_byte(ADDR_AIRGATE_POS); + pos = (val << STEPPING_MODE); +} + void setAirgate(uint8_t const target) { if (target == getAirgate() || isAirgateBusy() || isDriverFault()) { return; } - if (bit_is_clear(PORT, PIN_SLEEP)) { - setSleepMode(false); - } + setSleepMode(false); int16_t diff = (((int16_t)target) << STEPPING_MODE) - pos; if (diff != 0) { dir = (diff > 0) - (diff < 0); steps = abs(diff); ramp = MIN(abs(MAX_SPEED - MIN_SPEED), steps >> 1); start(); + eeprom_update_byte(ADDR_AIRGATE_POS, target); } } @@ -118,14 +125,14 @@ } bool isDriverFault(void) { - return bit_is_clear(PORT, PIN_FAULT); + return bit_is_clear(PIN, PIN_FAULT); } void setSleepMode(bool const on) { if (on) { PORT &= ~(1 << PIN_SLEEP); - } else { - // wake up driver + } else if (bit_is_clear(PORT, PIN_SLEEP)) { + // wake up driver if sleeping PORT |= (1 << PIN_SLEEP); // wakeup time _delay_ms(2); diff --git a/lambda/airgate.h b/lambda/airgate.h index c8e174f..7bcb4a1 100644 --- a/lambda/airgate.h +++ b/lambda/airgate.h @@ -39,8 +39,13 @@ void makeSteps(void); /** + * Gets the airgate position stored in EEPROM. + */ +void initAirgate(void); + +/** * Sets the airgate position 0 - 255, where 200 units correspond to 360° - * rotation (with 1.8° step angle). + * rotation (with 1.8° step angle). Stores the position in EEPROM. */ void setAirgate(uint8_t const position); diff --git a/lambda/eeprom.h b/lambda/eeprom.h new file mode 100644 index 0000000..1c29242 --- /dev/null +++ b/lambda/eeprom.h @@ -0,0 +1,13 @@ +/* + * eeprom.h + * + * Created on: 02.04.2016 + * Author: dode@luniks.net + */ + +#ifndef EEPROM_H_ +#define EEPROM_H_ + +#define ADDR_AIRGATE_POS (uint8_t *)0 + +#endif /* EEPROM_H_ */ diff --git a/lambda/lambda.c b/lambda/lambda.c index 5c4005f..4d9610a 100644 --- a/lambda/lambda.c +++ b/lambda/lambda.c @@ -55,6 +55,7 @@ setupSleepMode(); initInterrupts(); initTimers(); + initAirgate(); // wake up stepper motor driver setSleepMode(false); diff --git a/lambda/rules.c b/lambda/rules.c index cb695ad..b39c2f3 100644 --- a/lambda/rules.c +++ b/lambda/rules.c @@ -3,6 +3,11 @@ * * Created on: 22.05.2015 * Author: dode@luniks.net + * + * Evaluates the fire state like burning up and burning down and applies + * rules to control the airgate and issue notifications about certain + * operating and fault conditions. + * TODO door switch to be aware when the door of the firebox is open */ #include @@ -58,6 +63,8 @@ setSleepMode(true); } // put stepper motor driver in sleep mode in 60 seconds + // TODO could pass callback to setAirgate() and call it when position + // reached, or call from limit switch once there is one scheduleTask(func, 60); } @@ -228,9 +235,13 @@ * Notifies that the stepper motor driver signals fault condition. */ static void driverFault(bool* const fired, Measurement const meas) { - if (isDriverFault()) { + if (! *fired && isDriverFault()) { alert_P(BEEPS, LENGTH, TONE, PSTR(MSG_DRIVER_FAULT_0), PSTR(MSG_DRIVER_FAULT_1), true); + *fired = true; + } + if (*fired && ! isDriverFault()) { + *fired = false; } } diff --git a/lambda/sensors.c b/lambda/sensors.c index b6d47ee..7ca5e74 100644 --- a/lambda/sensors.c +++ b/lambda/sensors.c @@ -191,17 +191,17 @@ void setHeaterState(HeaterState const state) { if (state == heaterStateOn) { - PORTB |= (1 << PB2); + PORT |= (1 << PB2); heaterOnTime = getTime(); alert_P(1, 1, 31, PSTR(MSG_HEATER_UP_0), PSTR(MSG_HEATER_UP_1), true); } else if (state == heaterStateOff || state == heaterStateFault) { - PORTB &= ~(1 << PB2); + PORT &= ~(1 << PB2); } heaterState = state; } HeaterState getHeaterState(void) { - // bit_is_set(PORTB, PB2) + // bit_is_set(PORT, PB2) return heaterState; }