application: extend states and add central management

This commit is contained in:
King Kévin 2020-12-10 18:16:16 +01:00
parent 51cf8b0f95
commit dde56c996c
1 changed files with 192 additions and 36 deletions

View File

@ -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
}
}
}