2020-04-26 20:21:13 +02:00
|
|
|
/* Reflow Oven Controller
|
|
|
|
*
|
|
|
|
* Copyright (C) 2020 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/settings/settings-sd-card.h>
|
2020-08-16 01:24:20 +02:00
|
|
|
#include <stm-periph/unique-id.h>
|
|
|
|
#include <fatfs/ff.h>
|
2020-08-16 19:37:41 +02:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2020-11-01 00:59:46 +01:00
|
|
|
#include <config-parser/config-parser.h>
|
|
|
|
|
|
|
|
static char workbuff[256];
|
2020-08-16 01:24:20 +02:00
|
|
|
|
|
|
|
static void get_controller_folder_path(char *path, size_t size)
|
|
|
|
{
|
|
|
|
uint32_t high;
|
|
|
|
uint32_t mid;
|
|
|
|
uint32_t low;
|
|
|
|
|
|
|
|
if (!path)
|
|
|
|
return;
|
|
|
|
|
|
|
|
unique_id_get(&high, &mid, &low);
|
|
|
|
|
|
|
|
snprintf(path, size, "/%08X-%08X-%08X",
|
|
|
|
(unsigned int)high, (unsigned int)mid, (unsigned int)low);
|
|
|
|
}
|
|
|
|
|
2020-08-16 19:37:41 +02:00
|
|
|
static void get_controller_settings_path(char *path, size_t size, const char *setting)
|
|
|
|
{
|
|
|
|
char folder[48];
|
|
|
|
|
|
|
|
get_controller_folder_path(folder, sizeof(folder));
|
2020-11-01 00:59:46 +01:00
|
|
|
snprintf(path, size, "%s/%s.conf", folder, setting);
|
2020-08-16 19:37:41 +02:00
|
|
|
}
|
|
|
|
|
2020-08-16 01:24:20 +02:00
|
|
|
/**
|
|
|
|
* @brief Open or create the controller folder on the SD Card.
|
|
|
|
* @param[in,out] controller_folder
|
|
|
|
* @return 0 if opened, 1 if created and opened, -1 if error.
|
|
|
|
*/
|
2020-08-16 13:15:35 +02:00
|
|
|
static int create_controller_folder(void)
|
2020-08-16 01:24:20 +02:00
|
|
|
{
|
|
|
|
char foldername[48];
|
|
|
|
int ret = -1;
|
|
|
|
FRESULT filesystem_result;
|
2020-08-21 00:06:56 +02:00
|
|
|
FILINFO fno;
|
2020-08-16 01:24:20 +02:00
|
|
|
|
|
|
|
get_controller_folder_path(foldername, sizeof(foldername));
|
|
|
|
|
|
|
|
/* Check if folder is present */
|
2020-08-21 00:06:56 +02:00
|
|
|
filesystem_result = f_stat(foldername, &fno);
|
|
|
|
if (filesystem_result == FR_OK && fno.fattrib & AM_DIR) {
|
2020-08-16 01:24:20 +02:00
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
filesystem_result = f_mkdir(foldername);
|
|
|
|
if (filesystem_result == FR_OK) {
|
2020-08-16 13:15:35 +02:00
|
|
|
ret = 1;
|
2020-08-16 01:24:20 +02:00
|
|
|
} else {
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-16 19:37:41 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-08-16 01:24:20 +02:00
|
|
|
|
|
|
|
|
2020-08-16 12:52:16 +02:00
|
|
|
int sd_card_settings_save_calibration(float sens_deviation, float offset, bool active)
|
2020-08-16 01:24:20 +02:00
|
|
|
{
|
2020-11-01 00:59:46 +01:00
|
|
|
char path[200];
|
|
|
|
FRESULT res = FR_OK;
|
2020-11-01 21:24:13 +01:00
|
|
|
int ret = 0;
|
2020-08-16 19:37:41 +02:00
|
|
|
FIL file;
|
2020-08-16 01:24:20 +02:00
|
|
|
|
2020-11-01 00:59:46 +01:00
|
|
|
get_controller_settings_path(path, sizeof(path), "calibration");
|
2020-08-16 01:24:20 +02:00
|
|
|
|
2020-11-01 00:59:46 +01:00
|
|
|
if (create_controller_folder() < 0)
|
|
|
|
return -2;
|
2020-08-16 12:52:16 +02:00
|
|
|
|
2020-11-01 00:59:46 +01:00
|
|
|
if (!active) {
|
|
|
|
res = f_unlink(path);
|
|
|
|
goto check_fresult;
|
2020-08-16 19:37:41 +02:00
|
|
|
}
|
2020-08-16 12:52:16 +02:00
|
|
|
|
2020-11-01 00:59:46 +01:00
|
|
|
res = f_open(&file, path, FA_CREATE_ALWAYS | FA_WRITE);
|
|
|
|
if (res != FR_OK)
|
|
|
|
goto check_fresult;
|
|
|
|
|
|
|
|
snprintf(path, sizeof(path), "offset = %f\nsensitivity = %f\n", offset, sens_deviation);
|
|
|
|
ret = f_puts(path, &file);
|
|
|
|
if (ret < 0)
|
|
|
|
goto close_file;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
close_file:
|
|
|
|
res = f_close(&file);
|
|
|
|
check_fresult:
|
|
|
|
if (res != FR_OK)
|
|
|
|
return -2;
|
2020-08-16 19:37:41 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sd_card_settings_try_load_calibration(float *sens_deviation, float *offset)
|
|
|
|
{
|
|
|
|
char path[128];
|
2020-11-01 00:59:46 +01:00
|
|
|
int status = -1;
|
|
|
|
struct config_parser parser;
|
|
|
|
config_parser_handle_t p;
|
|
|
|
enum config_parser_ret res;
|
|
|
|
struct config_parser_entry entry;
|
|
|
|
bool sens_loaded = false;
|
|
|
|
bool offset_loaded = false;
|
2020-08-16 01:24:20 +02:00
|
|
|
|
2020-08-16 19:37:41 +02:00
|
|
|
if (!sens_deviation || !offset)
|
|
|
|
return -1000;
|
2020-08-16 01:24:20 +02:00
|
|
|
|
2020-11-01 00:59:46 +01:00
|
|
|
get_controller_settings_path(path, sizeof(path), "calibration");
|
|
|
|
p = config_parser_open_file(&parser, false, path, workbuff, sizeof(workbuff));
|
2021-01-01 17:31:35 +01:00
|
|
|
|
|
|
|
if (!p)
|
|
|
|
return status;
|
2020-11-01 00:59:46 +01:00
|
|
|
do {
|
2020-11-08 21:35:41 +01:00
|
|
|
res = config_parser_get_line(p, &entry, true);
|
2020-11-01 00:59:46 +01:00
|
|
|
if (res == CONFIG_PARSER_OK) {
|
|
|
|
if (!strcmp(entry.name, "offset") && entry.type == CONFIG_PARSER_TYPE_FLOAT) {
|
|
|
|
offset_loaded = true;
|
|
|
|
*offset = entry.value.float_val;
|
|
|
|
} else if (!strcmp(entry.name, "sensitivity") && entry.type == CONFIG_PARSER_TYPE_FLOAT) {
|
|
|
|
sens_loaded = true;
|
|
|
|
*sens_deviation = entry.value.float_val;
|
|
|
|
}
|
|
|
|
}
|
2020-08-16 19:37:41 +02:00
|
|
|
|
2020-11-29 19:03:17 +01:00
|
|
|
} while (!config_parser_ret_is_abort_condition(res));
|
2020-11-01 00:59:46 +01:00
|
|
|
|
2020-11-01 21:03:00 +01:00
|
|
|
config_parser_close_file(p);
|
|
|
|
|
2020-11-01 00:59:46 +01:00
|
|
|
if (sens_loaded && offset_loaded)
|
|
|
|
status = 0;
|
|
|
|
|
|
|
|
return status;
|
2020-08-16 01:24:20 +02:00
|
|
|
}
|
2020-11-08 21:35:41 +01:00
|
|
|
|
|
|
|
enum settings_load_result sd_card_settings_load_pid_oven_parameters(struct oven_pid_settings *settings)
|
|
|
|
{
|
|
|
|
enum settings_load_result ret = SETT_LOAD_ERR;
|
|
|
|
const char * const file_name = SETTINGS_PID_PARAMETER_FILE;
|
|
|
|
struct config_parser parser;
|
|
|
|
config_parser_handle_t p;
|
|
|
|
enum config_parser_ret parse_result;
|
|
|
|
struct config_parser_entry entry;
|
|
|
|
bool kp_loaded = false, kd_loaded = false, ki_loaded = false, int_max_loaded = false, t_sample = false;
|
|
|
|
|
|
|
|
if (!settings) {
|
|
|
|
ret = SETT_LOAD_ERR;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
workbuff[0] = 0;
|
|
|
|
p = config_parser_open_file(&parser, false, file_name, workbuff, sizeof(workbuff));
|
|
|
|
if (!p)
|
|
|
|
goto exit;
|
|
|
|
do {
|
|
|
|
parse_result = config_parser_get_line(p, &entry, true);
|
|
|
|
if (parse_result == CONFIG_PARSER_OK) {
|
|
|
|
if (!strcmp(entry.name, "kp")) {
|
|
|
|
kp_loaded = true;
|
|
|
|
settings->kp = entry.value.float_val;
|
|
|
|
} else if (!strcmp(entry.name, "kd")) {
|
|
|
|
kd_loaded = true;
|
|
|
|
settings->kd = entry.value.float_val;
|
|
|
|
} else if (!strcmp(entry.name, "ki")) {
|
|
|
|
ki_loaded = true;
|
|
|
|
settings->ki = entry.value.float_val;
|
|
|
|
} else if (!strcmp(entry.name, "max_int")) {
|
|
|
|
int_max_loaded = true;
|
|
|
|
settings->max_integral = entry.value.float_val;
|
|
|
|
} else if (!strcmp(entry.name, "sample_period")) {
|
|
|
|
t_sample = true;
|
|
|
|
settings->t_sample = entry.value.float_val / 1000.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-29 19:03:17 +01:00
|
|
|
} while (!config_parser_ret_is_abort_condition(parse_result));
|
2020-11-08 21:35:41 +01:00
|
|
|
|
|
|
|
|
|
|
|
if (kp_loaded && kd_loaded && ki_loaded && t_sample && int_max_loaded)
|
|
|
|
ret = SETT_LOAD_SUCCESS;
|
|
|
|
|
|
|
|
config_parser_close_file(p);
|
|
|
|
|
|
|
|
exit:
|
|
|
|
return ret;
|
|
|
|
}
|