Add temperature profile executer and add shell command
This commit is contained in:
parent
1b4eba1871
commit
1ecd5edd93
@ -51,6 +51,8 @@ CFILES += safety/safety-adc.c safety/safety-controller.c safety/watchdog.c safet
|
|||||||
CFILES += hw-version-detect.c
|
CFILES += hw-version-detect.c
|
||||||
CFILES += config-parser/config-parser.c config-parser/temp-profile-parser.c
|
CFILES += config-parser/config-parser.c config-parser/temp-profile-parser.c
|
||||||
CFILES += updater/updater.c
|
CFILES += updater/updater.c
|
||||||
|
CFILES += temp-profile-executer.c
|
||||||
|
|
||||||
INCLUDEPATH += -Iconfig-parser/include
|
INCLUDEPATH += -Iconfig-parser/include
|
||||||
|
|
||||||
CFILES += base64-lib/src/base64-lib.c
|
CFILES += base64-lib/src/base64-lib.c
|
||||||
|
@ -108,27 +108,37 @@ static int parse_line(char *line, struct pl_command *cmd)
|
|||||||
const char * const delim = " \t";
|
const char * const delim = " \t";
|
||||||
const struct pl_command_list_map *map;
|
const struct pl_command_list_map *map;
|
||||||
char *endptr;
|
char *endptr;
|
||||||
|
struct pl_command c;
|
||||||
|
|
||||||
if (!line || !cmd)
|
if (!line || !cmd)
|
||||||
return -1000;
|
return -1000;
|
||||||
|
|
||||||
token = strtok(line, delim);
|
token = strtok(line, delim);
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
/* Empty line or command line */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
while (token && token_idx <= PROFILE_LANG_MAX_NUM_ARGS) {
|
while (token && token_idx <= PROFILE_LANG_MAX_NUM_ARGS) {
|
||||||
switch (token_idx) {
|
switch (token_idx) {
|
||||||
case 0:
|
case 0:
|
||||||
map = string_to_command(token);
|
map = string_to_command(token);
|
||||||
cmd->cmd = map->command;
|
c.cmd = map->command;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (!map) {
|
if (!map) {
|
||||||
/* No valid command found */
|
/* No valid command found */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
cmd->params[token_idx - 1] = strtof(token, &endptr);
|
c.params[token_idx - 1] = strtof(token, &endptr);
|
||||||
if (endptr == token) {
|
if (endptr == token) {
|
||||||
/* Invalid parameter */
|
/* Invalid parameter */
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
if (token_idx > map->expected_param_count)
|
||||||
|
return -3;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +146,12 @@ static int parse_line(char *line, struct pl_command *cmd)
|
|||||||
token_idx++;
|
token_idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (token_idx - 1 < map->expected_param_count) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(cmd, &c, sizeof(struct pl_command));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,12 +196,14 @@ enum pl_ret_val temp_profile_parse_from_file(const char *filename,
|
|||||||
|
|
||||||
/* Parse the line */
|
/* Parse the line */
|
||||||
res = parse_line(workbuff, &cmd_list[cmd_idx]);
|
res = parse_line(workbuff, &cmd_list[cmd_idx]);
|
||||||
if (res) {
|
if (res < 0) {
|
||||||
ret = PL_RET_SCRIPT_ERR;
|
ret = PL_RET_SCRIPT_ERR;
|
||||||
goto exit_close;
|
goto exit_close;
|
||||||
|
} else if (res == 0) {
|
||||||
|
cmd_idx++;
|
||||||
|
*cmds_parsed= cmd_idx;
|
||||||
}
|
}
|
||||||
cmd_idx++;
|
|
||||||
*cmds_parsed= cmd_idx;
|
|
||||||
|
|
||||||
} while (!f_eof(&script_file));
|
} while (!f_eof(&script_file));
|
||||||
|
|
||||||
|
@ -35,8 +35,6 @@ void oven_driver_set_power(uint8_t power);
|
|||||||
|
|
||||||
void oven_driver_disable(void);
|
void oven_driver_disable(void);
|
||||||
|
|
||||||
void oven_pid_ack_errors(void);
|
|
||||||
|
|
||||||
void oven_pid_init(struct pid_controller *controller_to_copy);
|
void oven_pid_init(struct pid_controller *controller_to_copy);
|
||||||
|
|
||||||
void oven_pid_handle(void);
|
void oven_pid_handle(void);
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/* Reflow Oven Controller
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*
|
||||||
|
* This file is part of the Reflow Oven Controller Project.
|
||||||
|
*
|
||||||
|
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with the reflow oven controller project.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TEMP_PROFILE_EXECUTER_H__
|
||||||
|
#define __TEMP_PROFILE_EXECUTER_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <reflow-controller/config-parser/temp-profile-parser.h>
|
||||||
|
|
||||||
|
#define MAX_PROFILE_LENGTH 50
|
||||||
|
|
||||||
|
enum tpe_status {
|
||||||
|
TPE_OFF,
|
||||||
|
TPE_RUNNING,
|
||||||
|
TPE_ABORT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tpe_current_state {
|
||||||
|
enum tpe_status status;
|
||||||
|
float setpoint;
|
||||||
|
uint64_t start_timestamp;
|
||||||
|
uint32_t step;
|
||||||
|
uint32_t profile_steps;
|
||||||
|
enum pl_command_type current_command;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum pl_ret_val temp_profile_executer_start(const char *filename);
|
||||||
|
|
||||||
|
int temp_profile_executer_handle(void);
|
||||||
|
|
||||||
|
const struct tpe_current_state *temp_profile_executer_status(void);
|
||||||
|
|
||||||
|
int temp_profile_executer_stop(void);
|
||||||
|
|
||||||
|
#endif /* __TEMP_PROFILE_EXECUTER_H__ */
|
@ -46,7 +46,7 @@
|
|||||||
#include <reflow-controller/safety/safety-memory.h>
|
#include <reflow-controller/safety/safety-memory.h>
|
||||||
#include <reflow-controller/safety/fault.h>
|
#include <reflow-controller/safety/fault.h>
|
||||||
#include <reflow-controller/updater/updater.h>
|
#include <reflow-controller/updater/updater.h>
|
||||||
|
#include <reflow-controller/temp-profile-executer.h>
|
||||||
#include <reflow-controller/settings/spi-eeprom.h>
|
#include <reflow-controller/settings/spi-eeprom.h>
|
||||||
|
|
||||||
static void setup_nvic_priorities(void)
|
static void setup_nvic_priorities(void)
|
||||||
@ -253,6 +253,9 @@ int main(void)
|
|||||||
menu_wait_request = gui_handle();
|
menu_wait_request = gui_handle();
|
||||||
handle_shell_uart_input(shell_handle);
|
handle_shell_uart_input(shell_handle);
|
||||||
|
|
||||||
|
/* Execute current profile step, if a profile is active */
|
||||||
|
temp_profile_executer_handle();
|
||||||
|
|
||||||
safety_controller_handle();
|
safety_controller_handle();
|
||||||
if (oven_pid_get_status() == OVEN_PID_RUNNING) {
|
if (oven_pid_get_status() == OVEN_PID_RUNNING) {
|
||||||
oven_pid_handle();
|
oven_pid_handle();
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include <reflow-controller/safety/fault.h>
|
#include <reflow-controller/safety/fault.h>
|
||||||
#include <reflow-controller/safety/safety-memory.h>
|
#include <reflow-controller/safety/safety-memory.h>
|
||||||
#include <reflow-controller/hw-version-detect.h>
|
#include <reflow-controller/hw-version-detect.h>
|
||||||
|
#include <reflow-controller/temp-profile-executer.h>
|
||||||
|
|
||||||
#ifndef GIT_VER
|
#ifndef GIT_VER
|
||||||
#define GIT_VER "VERSION NOT SET"
|
#define GIT_VER "VERSION NOT SET"
|
||||||
@ -683,6 +684,58 @@ shellmatta_retCode_t shell_cmd_overtemp_cfg(const shellmatta_handle_t handle, co
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shellmatta_retCode_t shell_cmd_execute(const shellmatta_handle_t handle, const char *args, uint32_t len)
|
||||||
|
{
|
||||||
|
enum pl_ret_val res;
|
||||||
|
const struct tpe_current_state *state;
|
||||||
|
static bool running = false;
|
||||||
|
char *data;
|
||||||
|
uint32_t dlen;
|
||||||
|
|
||||||
|
shellmatta_read(handle, &data, &dlen);
|
||||||
|
|
||||||
|
if (!running) {
|
||||||
|
res = temp_profile_executer_start("profile.tpr");
|
||||||
|
|
||||||
|
if (res != PL_RET_SUCCESS) {
|
||||||
|
switch (res) {
|
||||||
|
case PL_RET_DISK_ERR:
|
||||||
|
shellmatta_printf(handle, "Error reading file\r\n");
|
||||||
|
break;
|
||||||
|
case PL_RET_LIST_FULL:
|
||||||
|
shellmatta_printf(handle, "Script too long!\r\n");
|
||||||
|
break;
|
||||||
|
case PL_RET_SCRIPT_ERR:
|
||||||
|
shellmatta_printf(handle, "Error in script\r\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
shellmatta_printf(handle, "Unspecified error occured\r\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SHELLMATTA_ERROR;
|
||||||
|
}
|
||||||
|
running = true;
|
||||||
|
} else {
|
||||||
|
state = temp_profile_executer_status();
|
||||||
|
if (state->status != TPE_RUNNING) {
|
||||||
|
shellmatta_printf(handle, "Profile executed.\r\n");
|
||||||
|
running = false;
|
||||||
|
if(state->status == TPE_ABORT) {
|
||||||
|
shellmatta_printf(handle, "Profile execution aborted!\r\n");
|
||||||
|
}
|
||||||
|
return SHELLMATTA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dlen > 0 && *data == '\x03') {
|
||||||
|
temp_profile_executer_stop();
|
||||||
|
return SHELLMATTA_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SHELLMATTA_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
//typedef struct shellmatta_cmd
|
//typedef struct shellmatta_cmd
|
||||||
//{
|
//{
|
||||||
// char *cmd; /**< command name */
|
// char *cmd; /**< command name */
|
||||||
@ -692,7 +745,7 @@ shellmatta_retCode_t shell_cmd_overtemp_cfg(const shellmatta_handle_t handle, co
|
|||||||
// shellmatta_cmdFct_t cmdFct; /**< pointer to the cmd callack function */
|
// shellmatta_cmdFct_t cmdFct; /**< pointer to the cmd callack function */
|
||||||
// struct shellmatta_cmd *next; /**< pointer to next command or NULL */
|
// struct shellmatta_cmd *next; /**< pointer to next command or NULL */
|
||||||
//} shellmatta_cmd_t;
|
//} shellmatta_cmd_t;
|
||||||
static shellmatta_cmd_t cmd[20] = {
|
static shellmatta_cmd_t cmd[21] = {
|
||||||
{
|
{
|
||||||
.cmd = "version",
|
.cmd = "version",
|
||||||
.cmdAlias = "ver",
|
.cmdAlias = "ver",
|
||||||
@ -852,6 +905,14 @@ static shellmatta_cmd_t cmd[20] = {
|
|||||||
.helpText = "Overtemperature Config",
|
.helpText = "Overtemperature Config",
|
||||||
.usageText = "",
|
.usageText = "",
|
||||||
.cmdFct = shell_cmd_overtemp_cfg,
|
.cmdFct = shell_cmd_overtemp_cfg,
|
||||||
|
.next = &cmd[20],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.cmd = "execute",
|
||||||
|
.cmdAlias = NULL,
|
||||||
|
.helpText = "Execute Temp Profile",
|
||||||
|
.usageText = "",
|
||||||
|
.cmdFct = shell_cmd_execute,
|
||||||
.next = NULL,
|
.next = NULL,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
216
stm-firmware/temp-profile-executer.c
Normal file
216
stm-firmware/temp-profile-executer.c
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
/* Reflow Oven Controller
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*
|
||||||
|
* This file is part of the Reflow Oven Controller Project.
|
||||||
|
*
|
||||||
|
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with the reflow oven controller project.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <reflow-controller/temp-profile-executer.h>
|
||||||
|
#include <reflow-controller/systick.h>
|
||||||
|
#include <helper-macros/helper-macros.h>
|
||||||
|
#include <reflow-controller/oven-driver.h>
|
||||||
|
#include <reflow-controller/temp-converter.h>
|
||||||
|
#include <reflow-controller/adc-meas.h>
|
||||||
|
#include <reflow-controller/digio.h>
|
||||||
|
|
||||||
|
static struct tpe_current_state IN_SECTION(.ccm.data) state = {
|
||||||
|
.status = TPE_OFF,
|
||||||
|
.start_timestamp = 0,
|
||||||
|
};
|
||||||
|
static bool IN_SECTION(.ccm.bss) pid_should_run;
|
||||||
|
struct pid_controller IN_SECTION(.ccm.bss) pid;
|
||||||
|
|
||||||
|
static struct pl_command IN_SECTION(.ccm.bss) cmd_list[MAX_PROFILE_LENGTH];
|
||||||
|
|
||||||
|
static void abort(void)
|
||||||
|
{
|
||||||
|
temp_profile_executer_stop();
|
||||||
|
state.status = TPE_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum pl_ret_val temp_profile_executer_start(const char *filename)
|
||||||
|
{
|
||||||
|
uint32_t parsed_count = 0;
|
||||||
|
enum pl_ret_val res;
|
||||||
|
|
||||||
|
state.setpoint = 0.0f;
|
||||||
|
state.start_timestamp = 0ULL;
|
||||||
|
state.setpoint = 0.0f;
|
||||||
|
state.step = 0;
|
||||||
|
state.profile_steps = 0;
|
||||||
|
|
||||||
|
oven_pid_stop();
|
||||||
|
pid_should_run = false;
|
||||||
|
|
||||||
|
res = temp_profile_parse_from_file(filename, cmd_list, MAX_PROFILE_LENGTH, &parsed_count);
|
||||||
|
if (res == PL_RET_SUCCESS) {
|
||||||
|
state.profile_steps = parsed_count;
|
||||||
|
state.status = TPE_RUNNING;
|
||||||
|
state.start_timestamp = systick_get_global_tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cmd_wait_temp(struct pl_command *cmd, bool cmd_continue)
|
||||||
|
{
|
||||||
|
(void)cmd_continue;
|
||||||
|
float resistance;
|
||||||
|
int res;
|
||||||
|
float temp;
|
||||||
|
|
||||||
|
res = adc_pt1000_get_current_resistance(&resistance);
|
||||||
|
if (res < 0) {
|
||||||
|
abort();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)temp_converter_convert_resistance_to_temp(resistance, &temp);
|
||||||
|
|
||||||
|
if (ABS(cmd->params[0] - temp) < 3.0f)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cmd_wait_time(struct pl_command *cmd, bool cmd_continue)
|
||||||
|
{
|
||||||
|
static uint64_t temp_tick = 0UL;
|
||||||
|
|
||||||
|
if (cmd_continue) {
|
||||||
|
if (systick_ticks_have_passed(temp_tick,
|
||||||
|
(uint64_t)(cmd->params[0] * 1000.0f)))
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
temp_tick = systick_get_global_tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reactivate_pid_if_suspended(void)
|
||||||
|
{
|
||||||
|
if (oven_pid_get_status() == OVEN_PID_DEACTIVATED)
|
||||||
|
oven_pid_init(&pid);
|
||||||
|
|
||||||
|
pid_should_run = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cmd_set_temp(struct pl_command *cmd, bool cmd_continue)
|
||||||
|
{
|
||||||
|
(void)cmd_continue;
|
||||||
|
|
||||||
|
reactivate_pid_if_suspended();
|
||||||
|
oven_pid_set_target_temperature(cmd->params[0]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int temp_profile_executer_handle(void)
|
||||||
|
{
|
||||||
|
struct pl_command *current_cmd;
|
||||||
|
static uint64_t last_tick = 0UL;
|
||||||
|
bool advance;
|
||||||
|
static bool cmd_continue = false;
|
||||||
|
uint32_t next_step;
|
||||||
|
|
||||||
|
|
||||||
|
if (state.status != TPE_RUNNING)
|
||||||
|
return -1;
|
||||||
|
if (oven_pid_get_status() == OVEN_PID_ABORTED && pid_should_run) {
|
||||||
|
abort();
|
||||||
|
oven_pid_stop();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (systick_ticks_have_passed(last_tick, 100)) {
|
||||||
|
current_cmd = &cmd_list[state.step];
|
||||||
|
next_step = state.step;
|
||||||
|
|
||||||
|
switch (current_cmd->cmd) {
|
||||||
|
case PL_WAIT_FOR_TIME:
|
||||||
|
advance = cmd_wait_time(current_cmd, cmd_continue);
|
||||||
|
break;
|
||||||
|
case PL_WAIT_FOR_TEMP:
|
||||||
|
advance = cmd_wait_temp(current_cmd, cmd_continue);
|
||||||
|
break;
|
||||||
|
case PL_SET_TEMP:
|
||||||
|
advance = cmd_set_temp(current_cmd, cmd_continue);
|
||||||
|
break;
|
||||||
|
case PL_LOUDSPEAKER_SET:
|
||||||
|
loudspeaker_set((uint16_t)current_cmd->params[0]);
|
||||||
|
advance = true;
|
||||||
|
break;
|
||||||
|
case PL_OFF:
|
||||||
|
oven_pid_stop();
|
||||||
|
pid_should_run = false;
|
||||||
|
advance = true;
|
||||||
|
break;
|
||||||
|
case PL_PID_CONF:
|
||||||
|
pid_init(&pid, current_cmd->params[0], /* Kd */
|
||||||
|
current_cmd->params[1], /* Ki */
|
||||||
|
current_cmd->params[2], /* Kp */
|
||||||
|
0.0f, 0.0f,
|
||||||
|
current_cmd->params[3], /* Int max */
|
||||||
|
current_cmd->params[4], /* Kd tau */
|
||||||
|
current_cmd->params[5]); /* Period */
|
||||||
|
oven_pid_init(&pid);
|
||||||
|
advance = true;
|
||||||
|
pid_should_run = true;
|
||||||
|
break;
|
||||||
|
case PL_SET_RAMP:
|
||||||
|
advance = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
advance = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (advance)
|
||||||
|
next_step++;
|
||||||
|
|
||||||
|
if (next_step != state.step) {
|
||||||
|
state.step = next_step;
|
||||||
|
if (next_step >= state.profile_steps) {
|
||||||
|
(void)temp_profile_executer_stop();
|
||||||
|
} else {
|
||||||
|
cmd_continue = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cmd_continue = true;
|
||||||
|
}
|
||||||
|
last_tick = systick_get_global_tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct tpe_current_state *temp_profile_executer_status(void)
|
||||||
|
{
|
||||||
|
return &state;
|
||||||
|
}
|
||||||
|
|
||||||
|
int temp_profile_executer_stop(void)
|
||||||
|
{
|
||||||
|
if (state.status == TPE_RUNNING) {
|
||||||
|
state.status = TPE_OFF;
|
||||||
|
oven_pid_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
loudspeaker_set(0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user