/* Reflow Oven Controller * * Copyright (C) 2021 Mario Hüttel * * 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 . */ #include #include #include #include #include struct pl_command_list_map { enum pl_command_type command; const char * const token; uint8_t expected_param_count; }; /** * @brief This list stores the command tokens and the expected number of arguments for each command */ static const struct pl_command_list_map cmd_list_map[_PL_NUM_CMDS] = { {PL_PID_CONF, "pid_conf", 6u}, {PL_SET_TEMP, "temp_set", 1u}, {PL_WAIT_FOR_TEMP, "wait_temp", 1u}, {PL_WAIT_FOR_TIME, "wait_time", 1u}, {PL_SET_RAMP, "temp_ramp", 2u}, {PL_LOUDSPEAKER_SET, "beep", 1u}, {PL_OFF, "temp_off", 0u} }; /** * @brief Read a line in the file until a line break is detected or a comment is started. * * In case a comment is detected, it is still read form the file to ensure * the next line is read afterwards * * @param f File to read from * @param buffer Buffer to read in * @param buffsize buffer size * @return 0 if successful, -1 if disk error, */ static int read_line_until_comment(FIL *f, char *buffer, uint32_t buffsize) { char *ptr; uint32_t i; if (!f || !buffsize || !buffer) return -1000; buffer[0] = 0; /* Read the line from file */ ptr = f_gets(buffer, (int)buffsize, f); if (!ptr) { buffer[0] = 0; return -2; } /* Go through the line until we encounter a # sign or the end of line*/ for (i = 0; i < buffsize; i++) { if (buffer[i] == '\n' || buffer[i] == '#') { buffer[i] = 0; break; } else if (buffer[i] == 0) { break; } } return 0; } static const struct pl_command_list_map *string_to_command(const char *str) { uint32_t i; const struct pl_command_list_map *ret = NULL; if (!str) return NULL; for (i = 0u; i < _PL_NUM_CMDS; i++) { if (!strcmp(str, cmd_list_map[i].token)) { ret = &cmd_list_map[i]; break; } } return ret; } static int parse_line(char *line, struct pl_command *cmd) { uint8_t token_idx = 0; char *token; const char * const delim = " \t"; const struct pl_command_list_map *map; char *endptr; if (!line || !cmd) return -1000; token = strtok(line, delim); while (token && token_idx <= PROFILE_LANG_MAX_NUM_ARGS) { switch (token_idx) { case 0: map = string_to_command(token); cmd->cmd = map->command; break; default: if (!map) { /* No valid command found */ return -1; } cmd->params[token_idx - 1] = strtof(token, &endptr); if (endptr == token) { /* Invalid parameter */ return -2; } break; } token = strtok(NULL, delim); token_idx++; } return 0; } enum pl_ret_val temp_profile_parse_from_file(const char *filename, struct pl_command *cmd_list, uint32_t cmd_list_length, uint32_t *cmds_parsed) { FIL script_file; FRESULT fres; int res; enum pl_ret_val ret = PL_RET_SUCCESS; char workbuff[256]; uint32_t cmd_idx; if (!filename || !cmd_list || !cmd_list_length || !cmds_parsed) return PL_RET_PARAM_ERR; fres = f_open(&script_file, filename, FA_READ); if (fres != FR_OK) { ret = PL_RET_DISK_ERR; goto exit; } cmd_idx = 0; *cmds_parsed = 0; do { /* read in the line */ res = read_line_until_comment(&script_file, workbuff, sizeof(workbuff)); if (res < 0) { ret = PL_RET_DISK_ERR; goto exit_close; } /* Check if list already full */ if (cmd_idx >= cmd_list_length) { ret = PL_RET_LIST_FULL; goto exit_close; } /* Parse the line */ res = parse_line(workbuff, &cmd_list[cmd_idx]); if (res) { ret = PL_RET_SCRIPT_ERR; goto exit_close; } cmd_idx++; *cmds_parsed= cmd_idx; } while (!f_eof(&script_file)); exit_close: (void)f_close(&script_file); exit: return ret; }