From dde56c996c68563286665a6dcc97144070cc2cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Thu, 10 Dec 2020 18:16:16 +0100 Subject: [PATCH] application: extend states and add central management --- application.c | 228 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 192 insertions(+), 36 deletions(-) diff --git a/application.c b/application.c index 33fb5c4..36328eb 100644 --- a/application.c +++ b/application.c @@ -125,8 +125,39 @@ enum state_e { STATE_SAFE, /**< safe state entered, probably because of an error */ STATE_HEAT, /**< simply heat up bed */ STATE_COOL, /**< simply cool down bed */ + STATE_FAN, /**< simply use fan to set to ambient temperature */ + STATE_PREPARE, /**< heat up for initialisation/first denaturation */ + STATE_INITIALISATION, /**< first (longer) denaturation phase */ + STATE_TO_DENATURATION, /**< transition to denaturation phase */ + STATE_DENATURATION, /**< denaturation phase */ + STATE_TO_ANNEALING, /**< transition to annealing phase */ + STATE_ANNEALING, /**< annealing phase */ + STATE_TO_EXTENSTION, /**< transition to extension phase */ + STATE_EXTENSION, /**< extension phase */ + STATE_TO_HOLD, /**< transition to final hold */ + STATE_HOLD, /**< final hold */ } state = STATE_IDLE; +/** name of the states */ +const char* state_names[] = { + [STATE_IDLE] = "ready", + [STATE_SAFE] = "safe", + [STATE_HEAT] = "heating", + [STATE_COOL] = "cooling", + [STATE_FAN] = "fanning", + [STATE_PREPARE] = ">initialisation", + [STATE_INITIALISATION] = "initialisation", + [STATE_TO_DENATURATION] = ">denaturation", + [STATE_DENATURATION] = "denaturation", + [STATE_TO_ANNEALING] = ">annealing", + [STATE_ANNEALING] = "annealing", + [STATE_TO_EXTENSTION] = ">extension", + [STATE_EXTENSION] = "extension", + // there is an optional final extension + [STATE_TO_HOLD] = ">final hold", + [STATE_HOLD] = "final hold", +}; + /** set if an error or anomaly has been encountered */ static char* error = NULL; @@ -151,8 +182,6 @@ size_t putc(char c) */ static void safe_state(void) { - state = STATE_SAFE; // remember we entered safe state - // this is the safest configuration of TEC switching (in cooling mode it switches all off, in heating mode it only heats mildly the top part gpio_set(GPIO_PORT(MBLK019_CH26_PIN), GPIO_PIN(MBLK019_CH26_PIN)); // don't sink current (e.g. not powering the opto-coupler/transistor) gpio_set(GPIO_PORT(MBLK019_CH14_PIN), GPIO_PIN(MBLK019_CH14_PIN)); // don't sink current (e.g. not powering the opto-coupler/transistor) @@ -177,13 +206,9 @@ static void safe_state(void) led_cool_blink = false; // stop blinking LED led_cool_off(); // switch off LED - oled_text_clear(); // clear screen - oled_text_line("safe", 0); // indicate state - oled_text_update(); // display text - if (error) { led_power_blink = false; // start blinking red LED to indicate error - oled_text_line("error", 1); + oled_text_line("error", 2); oled_text_update(); } } @@ -429,6 +454,155 @@ static void bed_pid(void) tec_power((uint16_t)power); // set power } +/** set new state + * @param[in] new new state to set + */ +static void set_state(enum state_e new) +{ + if (STATE_SAFE == state && STATE_SAFE != new) { + puts("restart controller to exit safe state\n"); + return; + } + + switch (new) { + case STATE_IDLE: // you can go to idle from any state (except safe) + tec_power(0); // ensure bed is not powered anymore + tec_power_yellow_off(); // disconnect all wires + tec_power_orange_off(); // disconnect all wires + lid_power(0); // ensure lid is not powered + break; + case STATE_SAFE: // go to safe state + safe_state(); // put all peripherals in safe mode + break; + case STATE_HEAT: + heatsink_fan_on(); // switch fan on + tec_power(0); // switch power off before changing mode + tec_heat(); // switch to heating mode + break; + case STATE_COOL: + heatsink_fan_on(); // switch fan on + tec_power(0); // switch power off before changing mode + tec_cool(); // switch to heating mode + break; + case STATE_FAN: + tec_power(0); // ensure bed is not powered anymore + tec_power_yellow_off(); // disconnect all wires + tec_power_orange_off(); // disconnect all wires + lid_power(0); // ensure lid is not powered + heatsink_fan_on(); // switch fan on + break; + case STATE_PREPARE: + if (STATE_IDLE == state) { // only allowed from idle state + bed_target = 95.0; // set target temperature + lid_target = bed_target; // set temperature + heatsink_fan_on(); // switch fan on + tec_power(0); // switch power off + tec_heat(); // switch to heating mode + // TODO set unlimited time + } else { // transition not allowed + set_state(STATE_SAFE); + } + break; + case STATE_INITIALISATION: + if (STATE_PREPARE == state) { // only allowed from state + // temperature and heating is already set + // TODO set time to 5 min + } else { // transition not allowed + set_state(STATE_SAFE); + } + break; + case STATE_TO_DENATURATION: + if (STATE_EXTENSION == state) { // only allowed from state + lid_target = 95.0; // set target temperature + bed_target = 95.0; // set target temperature + // heating is already set + // TODO set unlimited time + } else { // transition not allowed + set_state(STATE_SAFE); + } + break; + case STATE_DENATURATION: + if (STATE_TO_DENATURATION == state) { // only allowed from state + // temperature and heating is already set + // TODO set time to 5 min + } else { // transition not allowed + set_state(STATE_SAFE); + } + break; + case STATE_TO_ANNEALING: + if (STATE_DENATURATION == state) { // only allowed from state + bed_target = 45.0; // set target temperature (5 °C below primer) + lid_target = bed_target; // same temperature + tec_power(0); // switch power off + tec_cool(); // switch to cooling mode + // TODO set unlimited time + } else { // transition not allowed + set_state(STATE_SAFE); + } + break; + case STATE_ANNEALING: + if (STATE_TO_ANNEALING == state) { // only allowed from state + tec_power(0); // switch power off before switching mode + tec_heat(); // switch to heating mode + // temperature is already set + // TODO set time to 30-40 s + } else { // transition not allowed + set_state(STATE_SAFE); + } + break; + case STATE_TO_EXTENSTION: + if (STATE_ANNEALING == state) { // only allowed from state + bed_target = 72.0; // set target temperature + lid_target = bed_target; // set target temperature + // heating is already set + // TODO set unlimited time + } else { // transition not allowed + set_state(STATE_SAFE); + } + break; + case STATE_EXTENSION: + if (STATE_TO_EXTENSTION == state) { // only allowed from state + // temperature and heating is already set + // TODO set time to ~1 min/kb of expected product; 5-10 min on last cycle. + } else { // transition not allowed + set_state(STATE_SAFE); + } + break; + case STATE_TO_HOLD: + if (STATE_EXTENSION == state) { // only allowed from state + bed_target = 10.0; // set target temperature (5 °C below primer) + lid_target = NAN; // we don't need to heat anymore + lid_power(0); // switch power off + tec_power(0); // switch power off + tec_cool(); // switch to cooling mode + // TODO set unlimited time + } else { // transition not allowed + set_state(STATE_SAFE); + } + break; + case STATE_HOLD: + if (STATE_TO_HOLD == state) { // only allowed from state + // nothing to do, we just reached the final hold up + // TODO set time to 30-40 s + } else { // transition not allowed + set_state(STATE_SAFE); + } + break; + default: // unknown new state + error = "unknown state to set"; + set_state(STATE_SAFE); + break; + } + + // display state + if (new != state && STATE_SAFE != state) { + state = new; // save new state + printf("new state: %s\n", state_names[state]); // show new state + oled_text_line(state_names[state], 1); // set new state + oled_text_update(); // show on display + } +} + /** display available commands * @param[in] argument no argument required */ @@ -467,25 +641,17 @@ static void command_bed_power(void* argument) return; } if (0 == target) { // switch off - // turn all off - tec_power(0); // switch power off - tec_power_yellow_off(); // disconnect 12V from yellow TEC line - tec_power_orange_off(); // disconnect 12V from orange TEC line - heatsink_fan_off(); // we can switch the fan off now bed_target = 0; // remember we have no target - state = STATE_IDLE; // set new state + set_state(STATE_IDLE); // set new state + } else if (1 == target) { // just use fan + bed_target = 0; // remember we have no target + set_state(STATE_FAN); // set new state } else if (target > 0) { // heat - heatsink_fan_on(); // switch fan on - tec_power(0); // switch power off - tec_heat(); // switch to heating mode bed_target = target; // remember target - state = STATE_HEAT; // set new state + set_state(STATE_HEAT); // set new state } else { // cool - heatsink_fan_on(); // switch fan on - tec_power(0); // switch power off - tec_cool(); // switch to heating mode bed_target = -target; // remember target - state = STATE_COOL; // set new state + set_state(STATE_COOL); // set new state } } @@ -543,24 +709,14 @@ static void command_lid_temperature(void* argument) static void command_safe(void* argument) { (void)argument; // we won't use the argument - safe_state(); + set_state(STATE_SAFE); printf("in safe state\n"); } static void command_state(void* argument) { (void)argument; // we won't use the argument - switch (state) { - case STATE_IDLE: - puts("idle"); - break; - case STATE_SAFE: - puts("safe"); - break; - default: - puts("unknown state"); - break; - } + puts(state_names[state]); putc('\n'); if (error) { @@ -951,7 +1107,7 @@ void main(void) if (oled_text_setup()) { // setup OLED display with default slave address oled_text_clear(); // clear buffer (else last state is displayed) oled_text_line("PCR 3000", 0); - oled_text_line("system ready", 1); + oled_text_line(state_names[state], 1); // show state oled_text_update(); puts("OK\n"); } else { @@ -975,7 +1131,7 @@ void main(void) terminal_setup(); // start terminal if (error && STATE_SAFE != state) { // an error has occurred during initialisation - safe_state(); // go to safe state + set_state(STATE_SAFE); // go to safe state } else { led_power_on(); // indicate user we are ready } @@ -1078,7 +1234,7 @@ void main(void) error = "heat sink is getting too warm"; } if (error) { // an error has occurred - safe_state(); // go to safe state + set_state(STATE_SAFE); // go to safe state } } }