24 Commits

Author SHA1 Message Date
8576bf4231 Merge branch 'dev' into feature/28-profile-parser 2021-04-04 19:35:52 +02:00
6ebd74cb31 Safety Bug: Add meas ADC timing flag to output of the pt1000 read function so it becomes invalid in this case. 2021-04-04 19:35:32 +02:00
46125ba752 Issue #28: Implement first working draft of temperature profile GUI 2021-04-04 19:34:13 +02:00
6c9f90c986 Issue #28: Fix buf in profile executer 2021-04-04 19:33:33 +02:00
74defd5384 Add main loop cycle counter for debugging 2021-04-04 19:32:44 +02:00
5deac33949 Implement basic gui for profile selection. Still doesn't do anything 2021-04-04 17:43:31 +02:00
666353e3b7 Merge branch 'dev' into feature/28-profile-parser 2021-04-04 17:01:51 +02:00
df40ab1be7 Update base64 lib submodule 2021-03-23 22:19:43 +01:00
4c3574c2e2 Make project Cmake ready 2021-03-23 22:15:11 +01:00
289f49204d fisr draft of cmake buidl system. Update generation still missing 2021-03-21 22:38:22 +01:00
4bc98e6baf Merge branch 'dev' into feature/28-profile-parser 2021-03-21 21:08:38 +01:00
e50ce0d541 Add pictures of external watchdog 2021-03-21 21:08:19 +01:00
78b63c853f Issue #28: Start GUI for Temp Profile execution 2021-03-21 21:07:54 +01:00
a25b249d77 Issue #28: Improve script handling 2021-03-21 19:21:36 +01:00
e815442617 Pid Controller: Set integral term lower boundary to 0 2021-03-21 19:18:08 +01:00
60104df30e Issue #28: Write temperture ramp command 2021-03-20 01:02:33 +01:00
5ab911b4b6 Merge branch 'dev' into feature/28-profile-parser 2021-03-19 20:55:00 +01:00
08427cc589 Merge branch 'dev' into feature/28-profile-parser 2021-03-19 20:53:58 +01:00
ba6e0880b4 Merge branch 'dev' into feature/28-profile-parser 2021-03-19 20:52:13 +01:00
6a71416d2a Add void casts to unused parameters 2021-03-19 20:24:49 +01:00
1ecd5edd93 Add temperature profile executer and add shell command 2021-03-19 20:19:37 +01:00
1b4eba1871 Write parser for temp profile language. Not yet tested. 2021-03-19 16:58:14 +01:00
e3e4a6d926 Merge branch 'dev' into feature/28-profile-parser 2021-03-18 22:50:28 +01:00
93ff4959a2 Issue #28: Start Temp profile parser 2021-03-18 22:44:05 +01:00
25 changed files with 1045 additions and 322 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -15,3 +15,4 @@ reflow-controller.includes
*.config *.config
*.files *.files
*.user.* *.user.*
*.user

View File

@@ -0,0 +1,86 @@
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_CROSSCOMPILING 1)
cmake_minimum_required(VERSION 3.0)
set(CMAKE_TOOLCHAIN_FILE "arm-none-eabi-gcc.cmake")
project(reflow-controller)
if(NOT WIN32)
string(ASCII 27 Esc)
set(ColorReset "${Esc}[m")
set(ColorBold "${Esc}[1m")
set(Red "${Esc}[31m")
set(Green "${Esc}[32m")
set(Yellow "${Esc}[33m")
set(Blue "${Esc}[34m")
set(Magenta "${Esc}[35m")
set(Cyan "${Esc}[36m")
set(White "${Esc}[37m")
set(BoldRed "${Esc}[1;31m")
set(BoldGreen "${Esc}[1;32m")
set(BoldYellow "${Esc}[1;33m")
set(BoldBlue "${Esc}[1;34m")
set(BoldMagenta "${Esc}[1;35m")
set(BoldCyan "${Esc}[1;36m")
set(BoldWhite "${Esc}[1;37m")
endif()
execute_process(COMMAND bash -c "echo -n $(git describe --always --tags --dirty)"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_DESCRIBE)
set(ELFFILE ${PROJECT_NAME}.elf)
set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/stm32f407vet6_flash.ld)
add_compile_options(-Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter)
add_compile_options(-mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare)
set(GIT_DESCRIBE "${GIT_DESCRIBE}")
add_definitions(-DBASE64_LOOKUP_TABLE_SECTION=\".ccm.bss\" -DSHELLMATTA_HELP_ALIAS=\"?\" -DGIT_VER=${GIT_DESCRIBE} -DHSE_VALUE=8000000UL -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4)
add_subdirectory(updater/ram-code)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
message("${BoldGreen}Version: ${GIT_DESCRIBE}${ColorReset}")
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DDEBUGBUILD)
add_compile_options(-O0 -g)
ELSE()
add_definitions(-DDEBUGBUILD)
add_compile_options(-O3 -g)
add_link_options(-Wl,--gc-sections)
ENDIF(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_subdirectory(base64-lib)
aux_source_directory("." MAIN_SOURCES)
aux_source_directory("config-parser" CFG_PARSER_SRCS)
aux_source_directory("ui" UI_SRCS)
aux_source_directory("fatfs" FAT_SRCS)
aux_source_directory("fatfs/shimatta_sdio_driver" SDIO_SRCS)
aux_source_directory("boot" BOOT_SRCS)
aux_source_directory("setup" SETUP_SRCS)
aux_source_directory("stm-periph" STM_PERIPH_SRCS)
aux_source_directory("settings" SETTINGS_SRCS)
aux_source_directory("safety" SAFETY_SRCS)
aux_source_directory("shellmatta/src" SHELLMATTA_SRCS)
aux_source_directory("updater" UPDATER_SRCS)
add_executable(${ELFFILE} ${MAIN_SOURCES} ${CFG_PARSER_SRCS} ${UI_SRCS}
${FAT_SRCS} ${SDIO_SRCS} ${BOOT_SRCS} ${SETUP_SRCS}
${STM_PERIPH_SRCS} ${SETTINGS_SRCS} ${SAFETY_SRCS} ${SHELLMATTA_SRCS} ${UPDATER_SRCS}
)
add_dependencies(${ELFFILE} updater-ram-code-header-blob)
target_include_directories(${ELFFILE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/shellmatta/api ${CMAKE_CURRENT_SOURCE_DIR}/config-parser/include)
target_link_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles -T${LINKER_SCRIPT} -Wl,--print-memory-usage)
target_link_libraries(${ELFFILE} base64-lib)
target_include_directories(${ELFFILE} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/updater/ram-code/include/")

View File

@@ -1,224 +0,0 @@
################################Shimatta Makefile####################################
#CPU: STM32F407VET6
#Compiler: arm-none-eabi
#####################################################################################
#Add Files and Folders below#########################################################
CFILES = main.c syscalls.c setup/system_stm32f4xx.c systick.c boot/startup_stm32f407vx.c
ASFILES =
INCLUDEPATH = -Iinclude
OBJDIR_BASE = obj
TARGET_BASE = reflow-controller
LIBRARYPATH = -L.
LIBRARIES =
DEFINES = -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4 -DHSE_VALUE=8000000UL
MAPFILE_BASE = memory-mapping
LINKER_SCRIPT=stm32f407vet6_flash.ld
export GIT_VER = $(shell git describe --always --dirty --tags)
DEFINES += -DGIT_VER=$(GIT_VER)
ifneq ($(VERBOSE),true)
QUIET=@
else
QUIET=
endif
##Custom Files###
CFILES += adc-meas.c
# Shellmatta
CFILES += shellmatta/src/shellmatta.c shellmatta/src/shellmatta_autocomplete.c shellmatta/src/shellmatta_escape.c shellmatta/src/shellmatta_history.c shellmatta/src/shellmatta_utils.c shellmatta/src/shellmatta_opt.c shell.c
INCLUDEPATH += -Ishellmatta/api
DEFINES += -DSHELLMATTA_HELP_ALIAS=\"?\"
# RCC Manager
CFILES += stm-periph/rcc-manager.c
CFILES += stm-periph/uart.c stm-periph/dma-ring-buffer.c stm-periph/backup-ram.c
CFILES += stm-periph/rng.c stm-periph/spi.c
CFILES += digio.c
CFILES += stm-periph/unique-id.c
CFILES += calibration.c
CFILES += temp-converter.c
CFILES += rotary-encoder.c button.c
CFILES += ui/lcd.c ui/menu.c ui/gui.c
CFILES += fatfs/diskio.c fatfs/ff.c fatfs/ffsystem.c fatfs/ffunicode.c fatfs/shimatta_sdio_driver/shimatta_sdio.c
CFILES += pid-controller.c oven-driver.c
CFILES += settings/settings.c settings/settings-sd-card.c settings/spi-eeprom.c settings/settings-eeprom.c
CFILES += stm-periph/crc-unit.c
CFILES += safety/safety-adc.c safety/safety-controller.c safety/watchdog.c safety/fault.c safety/safety-memory.c safety/stack-check.c
CFILES += hw-version-detect.c
CFILES += config-parser/config-parser.c
CFILES += updater/updater.c
INCLUDEPATH += -Iconfig-parser/include
CFILES += base64-lib/src/base64-lib.c
INCLUDEPATH += -Ibase64-lib/include
DEFINES += -DBASE64_LOOKUP_TABLE_SECTION="\".ccm.bss\""
DEBUG_DEFINES = -DDEBUGBUILD
RELEASE_DEFINES = -DUART_ON_DEBUG_HEADER
###################################################################################
ifeq ($(CROSS_COMPILE),)
CROSS_COMPILE=arm-none-eabi-
endif
CC=$(CROSS_COMPILE)gcc
OBJCOPY=$(CROSS_COMPILE)objcopy
OBJDUMP=$(CROSS_COMPILE)objdump
SIZE=$(CROSS_COMPILE)size
CFLAGS_RELEASE = -O3 -g
CFLAGS_DEBUG = -O0 -g
LFLAGS_RELEASE = -Wl,--gc-sections
LFLAGS_DEBUG =
CFLAGS =
LFLAGS =
ifneq ($(DEBUGBUILD),true)
DEFINES += $(RELEASE_DEFINES)
CFLAGS += $(CFLAGS_RELEASE)
LFLAGS += $(LFLAGS_RELEASE)
target = $(TARGET_BASE)-release
OBJDIR = $(OBJDIR_BASE)/release
MAPFILE = $(MAPFILE_BASE)-release
else
DEFINES += $(DEBUG_DEFINES)
target = $(TARGET_BASE)-debug
CFLAGS += $(CFLAGS_DEBUG)
LFLAGS += $(LFLAGS_DEBUG)
OBJDIR = $(OBJDIR_BASE)/debug
MAPFILE = $(MAPFILE_BASE)-debug
endif
LFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
LFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles
LFLAGS += -T$(LINKER_SCRIPT) -Wl,-Map=$(MAPFILE).map -Wl,--print-memory-usage
CFLAGS += -c -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles
CFLAGS += -Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter -Wimplicit-fallthrough=3 -Wsign-compare
####################################################################################
OBJ = $(CFILES:%.c=$(OBJDIR)/%.c.o)
ASOBJ += $(ASFILES:%.S=$(OBJDIR)/%.S.o)
default: $(target).elf
all: debug release
release:
$(QUIET)$(MAKE) DEBUGBUILD=false
debug:
$(QUIET)$(MAKE) DEBUGBUILD=true
%.bin: %.elf
$(QUIET)$(OBJCOPY) -O binary $^ $@
%.hex: %.elf
$(QUIET)$(OBJCOPY) -O ihex $^ $@
#Linking
$(target).elf: $(OBJ) $(ASOBJ) $(LINKER_SCRIPT)
@echo [LD] $@
$(QUIET)$(CC) $(LFLAGS) $(LIBRARYPATH) -o $@ $(OBJ) $(ASOBJ) $(LIBRARIES)
$(QUIET)$(SIZE) $@
@echo "Built Version $(GIT_VER)"
$(OBJDIR)/updater/updater.c.o: updater/ram-code/updater-ram-code.bin.h
#Compiling
$(OBJ):
@echo [CC] $@
$(eval OUTPATH=$(dir $@))
@mkdir -p $(OUTPATH)
$(QUIET)$(CC) $(CFLAGS) -MMD -MT $@ $(INCLUDEPATH) $(DEFINES) -o $@ $(@:$(OBJDIR)/%.c.o=%.c)
$(ASOBJ):
@echo [AS] $@
$(eval OUTPATH=$(dir $@))
@mkdir -p $(OUTPATH)
$(QUIET)$(CC) $(CFLAGS) -MMD -MT $@ $(INCLUDEPATH) $(DEFINES) -o $@ $(@:$(OBJDIR)/%.S.o=%.S)
.PHONY: qtproject-legacy qtproject qtproject-debug clean mrproper objcopy disassemble program program-debug updater/ram-code/updater-ram-code.bin.h
updater/ram-code/updater-ram-code.bin.h:
$(QUIET)$(MAKE) -C updater/ram-code updater-ram-code.bin.h
program-debug:
$(QUIET)$(MAKE) DEBUGBUILD=true program
program: $(target).elf
./program-device.sh $<
disassemble: $(target).elf
$(QUIET)$(OBJDUMP) -D -s $< > $(target).lss
objcopy: $(target).bin $(target).hex
mrproper: clean
ifneq ($(DEBUGBUILD),true)
@echo "Purging RELEASE project files"
else
@echo "Purging DEBUG project files"
endif
$(QUIET)rm -f $(target).pro $(target).creator $(target).files $(target).cflags $(target).cxxflags $(target).includes $(target).config
ifneq ($(DEBUGBUILD),true)
$(QUIET)$(MAKE) DEBUGBUILD=true mrproper
endif
clean:
@echo -n "Cleaning up derived files for "
ifneq ($(DEBUGBUILD),true)
@echo "RELEASE build"
else
@echo "DEBUG build"
endif
$(QUIET)rm -f $(target).elf $(target).bin $(target).hex $(OBJ) $(ASOBJ) $(mapfile).map $(CFILES:%.c=$(OBJDIR)/%.c.d) $(ASFILES:%.S=$(OBJDIR)/%.S.d)
$(QUIET)rm -rf $(OBJDIR)/*
$(MAKE) -C updater/ram-code clean
ifneq ($(DEBUGBUILD),true)
$(QUIET)$(MAKE) DEBUGBUILD=true clean
endif
qtproject-legacy:
echo -e "TEMPLATE = app\nCONFIG -= console app_bundle qt" > $(target).pro
echo -e "SOURCES += $(CFILES) $(ASFILES)" >> $(target).pro
echo -ne "INCLUDEPATH += " >> $(target).pro
echo "$(INCLUDEPATH)" | sed "s!-I!./!g" >> $(target).pro
echo -ne "HEADERS += " >> $(target).pro
find -name "*.h" | tr "\\n" " " >> $(target).pro
echo -ne "\nDEFINES += " >> $(target).pro
echo "$(DEFINES)" | sed "s/-D//g" >> $(target).pro
qtproject-debug:
@echo "Generating debug build project"
$(QUIET)$(MAKE) DEBUGBUILD=true qtproject
qtproject:
$(QUIET)rm -f $(target).files $(target).cflags $(target).config $(target).creator $(target).includes $(target).creator.user
@echo "Generating source file list"
$(QUIET)echo "$(CFILES)" | tr ' ' '\n' > $(target).files
@echo -n "Appending found header files from folders "
@echo `echo $(INCLUDEPATH) | sed "s/-I//g"`
$(QUIET)for dir in `echo $(INCLUDEPATH) | sed "s/-I//g"`; do \
find `echo "$${dir}"` -name "*.h" >> $(target).files; \
done
@echo "Generating $(target).cflags"
$(QUIET)echo "" > $(target).cflags
@echo "Generating $(target).includes"
$(QUIET)echo $(INCLUDEPATH) | sed "s/-I/,/g" | tr , '\n' | sed "/^$$/d" > $(target).includes;
@echo "Generating $(target).config"
$(QUIET)echo $(DEFINES) | sed "s/-D/,#define /g" | tr , '\n' | sed "/^$$/d" > $(target).config
@echo "Generating $(target).creator"
$(QUIET)echo "[GENERAL]" > $(target).creator
-include $(CFILES:%.c=$(OBJDIR)/%.c.d) $(ASFILES:%.S=$(OBJDIR)/%.S.d)

View File

@@ -232,7 +232,7 @@ int adc_pt1000_get_current_resistance(float *resistance)
*resistance = adc_pt1000_apply_calibration(pt1000_res_raw_lf); *resistance = adc_pt1000_apply_calibration(pt1000_res_raw_lf);
if (safety_controller_get_flags_by_mask(ERR_FLAG_MEAS_ADC_OFF | ERR_FLAG_MEAS_ADC_OVERFLOW | if (safety_controller_get_flags_by_mask(ERR_FLAG_MEAS_ADC_OFF | ERR_FLAG_MEAS_ADC_OVERFLOW |
ERR_FLAG_MEAS_ADC_WATCHDOG)) { ERR_FLAG_MEAS_ADC_WATCHDOG | ERR_FLAG_TIMING_MEAS_ADC)) {
ret_val = -100; ret_val = -100;
goto return_value; goto return_value;
} }

View File

@@ -0,0 +1,28 @@
if(MINGW OR CYGWIN OR WIN32)
set(UTIL_SEARCH_CMD where)
elseif(UNIX OR APPLE)
set(UTIL_SEARCH_CMD which)
endif()
set(TOOLCHAIN_PREFIX arm-none-eabi-)
execute_process(
COMMAND ${UTIL_SEARCH_CMD} ${TOOLCHAIN_PREFIX}gcc
OUTPUT_VARIABLE BINUTILS_PATH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
get_filename_component(ARM_TOOLCHAIN_DIR ${BINUTILS_PATH} DIRECTORY)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc)
set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++)
set(CMAKE_OBJCOPY ${ARM_TOOLCHAIN_DIR}/${TOOLCHAIN_PREFIX}objcopy CACHE INTERNAL "objcopy tool")
set(CMAKE_SIZE_UTIL ${ARM_TOOLCHAIN_DIR}/${TOOLCHAIN_PREFIX}size CACHE INTERNAL "size tool")
set(CMAKE_FIND_ROOT_PATH ${BINUTILS_PATH})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

View File

@@ -0,0 +1,214 @@
/* 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/config-parser/temp-profile-parser.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <fatfs/ff.h>
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;
struct pl_command c;
if (!line || !cmd)
return -1000;
token = strtok(line, delim);
if (!token) {
/* Empty line or command line */
return 1;
}
while (token && token_idx <= PROFILE_LANG_MAX_NUM_ARGS) {
switch (token_idx) {
case 0:
map = string_to_command(token);
c.cmd = map->command;
break;
default:
if (!map) {
/* No valid command found */
return -1;
}
c.params[token_idx - 1] = strtof(token, &endptr);
if (endptr == token) {
/* Invalid parameter */
return -2;
}
if (token_idx > map->expected_param_count)
return -3;
break;
}
token = strtok(NULL, delim);
token_idx++;
}
if (token_idx - 1 < map->expected_param_count) {
return -3;
}
memcpy(cmd, &c, sizeof(struct pl_command));
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 < 0) {
ret = PL_RET_SCRIPT_ERR;
goto exit_close;
} else if (res == 0) {
cmd_idx++;
*cmds_parsed= cmd_idx;
}
} while (!f_eof(&script_file));
exit_close:
(void)f_close(&script_file);
exit:
return ret;
}

View File

@@ -33,7 +33,7 @@
/ 2: Enable with LF-CRLF conversion. */ / 2: Enable with LF-CRLF conversion. */
#define FF_USE_FIND 0 #define FF_USE_FIND 1
/* This option switches filtered directory read functions, f_findfirst() and /* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */

View File

@@ -0,0 +1,57 @@
/* 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 __CONFIG_PARSER_TEMP_PROFILE_PARSER_H__
#define __CONFIG_PARSER_TEMP_PROFILE_PARSER_H__
#include <stdint.h>
enum pl_command_type {
PL_PID_CONF = 0,
PL_SET_TEMP,
PL_SET_RAMP,
PL_WAIT_FOR_TEMP,
PL_WAIT_FOR_TIME,
PL_LOUDSPEAKER_SET,
PL_OFF,
_PL_NUM_CMDS,
};
enum pl_ret_val {
PL_RET_SUCCESS = 0,
PL_RET_DISK_ERR,
PL_RET_PARAM_ERR,
PL_RET_LIST_FULL,
PL_RET_SCRIPT_ERR,
};
#define PROFILE_LANG_MAX_NUM_ARGS (8)
struct pl_command {
enum pl_command_type cmd;
float params[PROFILE_LANG_MAX_NUM_ARGS];
};
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);
#endif /* __CONFIG_PARSER_TEMP_PROFILE_PARSER_H__ */

View 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);

View File

@@ -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__ */

View File

@@ -87,4 +87,6 @@ void menu_list_scroll_up(struct menu_list *list);
void menu_list_enter_selected_entry(struct menu_list *list, struct lcd_menu *menu); void menu_list_enter_selected_entry(struct menu_list *list, struct lcd_menu *menu);
uint32_t menu_list_get_currently_selected(struct menu_list *list);
#endif /* __MENU_H__ */ #endif /* __MENU_H__ */

View File

@@ -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)
@@ -218,6 +218,7 @@ int main(void)
shellmatta_handle_t shell_handle; shellmatta_handle_t shell_handle;
int menu_wait_request; int menu_wait_request;
uint64_t quarter_sec_timestamp = 0ULL; uint64_t quarter_sec_timestamp = 0ULL;
static uint64_t IN_SECTION(.ccm.bss) main_loop_iter_count;
setup_system(); setup_system();
@@ -253,6 +254,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();
@@ -264,6 +268,7 @@ int main(void)
__WFI(); __WFI();
else else
__NOP(); __NOP();
main_loop_iter_count++;
} }
return 0; return 0;

View File

@@ -1,3 +0,0 @@
*
*.*
!.gitignore

View File

@@ -65,8 +65,8 @@ static void calculate_integral(struct pid_controller *pid, float deviation)
/* Saturate integral term to specified maximum */ /* Saturate integral term to specified maximum */
if (pid->integral > pid->integral_max) if (pid->integral > pid->integral_max)
pid->integral = pid->integral_max; pid->integral = pid->integral_max;
else if (pid->integral < -pid->integral_max) else if (pid->integral < 0.0f)
pid->integral = -pid->integral_max; pid->integral = 0.0f;
} }
float pid_sample(struct pid_controller *pid, float deviation) float pid_sample(struct pid_controller *pid, float deviation)

View File

@@ -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"
@@ -650,6 +651,8 @@ shellmatta_retCode_t shell_cmd_overtemp_cfg(const shellmatta_handle_t handle, co
char option; char option;
bool temp_passed = false; bool temp_passed = false;
bool persistent = false; bool persistent = false;
(void)args;
(void)len;
static const shellmatta_opt_long_t options[] = { static const shellmatta_opt_long_t options[] = {
{"persistent", 'p', SHELLMATTA_OPT_ARG_NONE}, {"persistent", 'p', SHELLMATTA_OPT_ARG_NONE},
@@ -683,6 +686,87 @@ 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;
(void)args;
(void)len;
int opt_stat;
char option;
char *argument;
uint32_t arg_len;
const char *script_name = NULL;
const shellmatta_opt_long_t options[] = {
{NULL, '\0', SHELLMATTA_OPT_ARG_NONE},
};
while (1) {
opt_stat = shellmatta_opt_long(handle, options, &option, &argument, &arg_len);
if (opt_stat != SHELLMATTA_OK)
break;
switch (option) {
case '\0':
script_name = argument;
break;
default:
break;
}
}
if (!script_name) {
shellmatta_printf(handle, "No script name specified!\r\n");
return SHELLMATTA_ERROR;
}
shellmatta_read(handle, &data, &dlen);
if (!running) {
res = temp_profile_executer_start(script_name);
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();
running = false;
return SHELLMATTA_OK;
}
}
return SHELLMATTA_CONTINUE;
}
//typedef struct shellmatta_cmd //typedef struct shellmatta_cmd
//{ //{
// char *cmd; /**< command name */ // char *cmd; /**< command name */
@@ -692,7 +776,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 +936,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 = "execute /path/to/script.tpr",
.cmdFct = shell_cmd_execute,
.next = NULL, .next = NULL,
} }
}; };

View File

@@ -0,0 +1,256 @@
/* 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;
bool IN_SECTION(.ccm.bss) cmd_continue;
static struct pl_command IN_SECTION(.ccm.bss) cmd_list[MAX_PROFILE_LENGTH];
static void tpe_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;
state.status = TPE_OFF;
state.profile_steps = 0;
cmd_continue = 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) {
tpe_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]);
state.setpoint = cmd->params[0];
return true;
}
static bool cmd_ramp(struct pl_command *cmd, bool cmd_continue)
{
static uint64_t IN_SECTION(.ccm.bss) start_timestamp;
static float IN_SECTION(.ccm.bss) start_temp;
static float IN_SECTION(.ccm.bss) slope;
float secs_passed;
bool ret = false;
if (!cmd_continue) {
/* Init of command */
start_temp = state.setpoint;
slope = (cmd->params[0] - start_temp) / cmd->params[1];
reactivate_pid_if_suspended();
oven_pid_set_target_temperature(start_temp);
start_timestamp = systick_get_global_tick();
} else {
secs_passed = ((float)(systick_get_global_tick() - start_timestamp)) / 1000.0f;
if ((state.setpoint <= cmd->params[0] && start_temp < cmd->params[0]) ||
(state.setpoint >= cmd->params[0] && start_temp > cmd->params[0])) {
state.setpoint = start_temp + secs_passed * slope;
} else {
state.setpoint = cmd->params[0];
ret = true;
}
oven_pid_set_target_temperature(state.setpoint);
}
return ret;
}
int temp_profile_executer_handle(void)
{
struct pl_command *current_cmd;
static uint64_t last_tick = 0UL;
bool advance;
uint32_t next_step;
/* Return if no profile is currently executed */
if (state.status != TPE_RUNNING)
return -1;
/* Abort profile execution if oven PID is aborted. This is most likely due to some error flags */
if (oven_pid_get_status() == OVEN_PID_ABORTED && pid_should_run) {
tpe_abort();
oven_pid_stop();
return -1;
}
/* Execute Temp Profile every 100 ms. If not yet due, return */
if (!systick_ticks_have_passed(last_tick, 100))
return 0;
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 = cmd_ramp(current_cmd, cmd_continue);
break;
default:
tpe_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;
}

View File

@@ -36,6 +36,8 @@
#include <string.h> #include <string.h>
#include <inttypes.h> #include <inttypes.h>
#include <reflow-controller/oven-driver.h> #include <reflow-controller/oven-driver.h>
#include <fatfs/ff.h>
#include <reflow-controller/temp-profile-executer.h>
static char IN_SECTION(.ccm.bss) display_buffer[4][21] = {0}; static char IN_SECTION(.ccm.bss) display_buffer[4][21] = {0};
static struct lcd_menu IN_SECTION(.ccm.bss) reflow_menu; static struct lcd_menu IN_SECTION(.ccm.bss) reflow_menu;
@@ -198,7 +200,7 @@ static void gui_menu_about(struct lcd_menu *menu, enum menu_entry_func_entry ent
uptime_secs = new_uptime_secs; uptime_secs = new_uptime_secs;
menu_lcd_output(menu, 0, "Uptime:"); menu_lcd_output(menu, 0, "Uptime:");
menu_lcd_outputf(menu, 1, "%lu day%s %02lu:%02lu:%02lu", menu_lcd_outputf(menu, 1, "%lu day%s %02lu:%02lu:%02lu",
uptime_days, (uptime_days == 1 ? "" : "s"), uptime_hours, uptime_mins, uptime_secs); uptime_days, (uptime_days == 1 ? "" : "s"), uptime_hours, uptime_mins, uptime_secs);
menu_lcd_output(menu, 3, "Page 5/5"); menu_lcd_output(menu, 3, "Page 5/5");
} }
break; break;
@@ -215,7 +217,7 @@ static void gui_menu_about(struct lcd_menu *menu, enum menu_entry_func_entry ent
button_ready = true; button_ready = true;
if (button_ready && if (button_ready &&
(push_button == BUTTON_SHORT_RELEASED || push_button == BUTTON_LONG)) { (push_button == BUTTON_SHORT_RELEASED || push_button == BUTTON_LONG)) {
menu_entry_dropback(menu, my_parent); menu_entry_dropback(menu, my_parent);
} }
} }
@@ -372,6 +374,189 @@ static void gui_menu_constant_temperature_driver(struct lcd_menu *menu, enum men
} }
/**
* @brief load_temperature_file_list_from_sdcard
* @return -1 File error, 0 successful
*/
static int load_temperature_file_list_from_sdcard(char (*list)[17], uint32_t len)
{
uint32_t i, j;
DIR directory;
FILINFO finfo;
FRESULT fres;
if (!list)
return -1001;
/* Zero out the list */
for (i = 0; i < len; i++) {
for (j = 0; j < sizeof(*list); j++) {
list[i][j] = 0;
}
}
/* find the frist file */
fres = f_findfirst(&directory, &finfo, "/", "*.tpr");
i = 0;
while (fres == FR_OK && finfo.fname[0]) {
strncpy(list[i], finfo.fname, sizeof(*list));
fres = f_findnext(&directory, &finfo);
i++;
if (i >= len)
break;
}
if (fres != FR_OK) {
return -1;
}
return (int)i;
}
static void gui_menu_temp_profile_execute(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void* parent)
{
static void *my_parent;
const struct tpe_current_state *state;
static uint64_t last_tick;
float temperature;
float resistance;
int res;
if (entry_type == MENU_ENTRY_FIRST_ENTER) {
my_parent = parent;
menu_display_clear(menu);
last_tick = 0ULL;
}
if (systick_ticks_have_passed(last_tick, 300)) {
state = temp_profile_executer_status();
if (state->status == TPE_RUNNING)
menu_lcd_outputf(menu, 0, "Profile running");
else if (state->status == TPE_OFF) {
menu_lcd_outputf(menu, 0, "Profile finished");
} else {
menu_lcd_outputf(menu, 0, "Profile aborted!");
}
menu_lcd_outputf(menu, 1, "Step %u/%u", state->step, state->profile_steps);
(void)adc_pt1000_get_current_resistance(&resistance);
res = temp_converter_convert_resistance_to_temp(resistance, &temperature);
menu_lcd_outputf(menu, 2, "Temp: %s%.0f", (res < 0 ? "<" : (res > 0 ? ">" : "")), temperature);
if (oven_pid_get_status() == OVEN_PID_RUNNING) {
menu_lcd_outputf(menu, 3, "Target: %.0f", state->setpoint);
} else {
menu_lcd_outputf(menu, 3, "Temp Off");
}
last_tick = systick_get_global_tick();
}
if (menu_get_button_ready_state(menu)) {
if (menu_get_button_state(menu) != BUTTON_IDLE) {
temp_profile_executer_stop();
menu_entry_dropback(menu, my_parent);
}
}
}
static void gui_menu_temp_profile_select(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent)
{
static void *my_parent;
static char profile_list[10][17];
static bool file_error = false;
static enum pl_ret_val profile_ret_val = PL_RET_SUCCESS;
static uint8_t currently_selected = 0U;
static uint8_t loaded;
int16_t delta;
enum button_state button;
int res;
if (entry_type == MENU_ENTRY_FIRST_ENTER) {
menu_display_clear(menu);
my_parent = parent;
res = load_temperature_file_list_from_sdcard(profile_list, 10);
file_error = false;
loaded = 0;
if (res < 0) {
file_error = true;
}
currently_selected = 0u;
profile_ret_val = PL_RET_SUCCESS;
loaded = (uint32_t)res;
menu_lcd_outputf(menu, 0, "Select:");
} else if (entry_type == MENU_ENTRY_DROPBACK) {
menu_entry_dropback(menu, my_parent);
return;
}
if (menu_get_button_ready_state(menu)) {
delta = menu_get_rotary_delta(menu);
button = menu_get_button_state(menu);
if (button == BUTTON_LONG) {
menu_entry_dropback(menu, my_parent);
}
if (file_error) {
menu_lcd_outputf(menu, 0, "Disk Error");
menu_lcd_outputf(menu, 1, "SD inserted?");
if (button == BUTTON_SHORT_RELEASED)
menu_entry_dropback(menu, my_parent);
return;
} else if (loaded == 0) {
menu_lcd_outputf(menu, 0, "No profiles");
menu_lcd_outputf(menu, 1, "found");
if (button == BUTTON_SHORT_RELEASED)
menu_entry_dropback(menu, my_parent);
return;
} else if (profile_ret_val != PL_RET_SUCCESS) {
menu_lcd_outputf(menu, 0, "ERROR");
switch (profile_ret_val) {
case PL_RET_SCRIPT_ERR:
menu_lcd_outputf(menu, 1, "Syntax Error");
break;
case PL_RET_DISK_ERR:
menu_lcd_outputf(menu, 1, "Disk Error");
break;
case PL_RET_LIST_FULL:
menu_lcd_output(menu, 1, "Too many com-");
menu_lcd_output(menu, 2, "mands in file");
break;
default:
menu_lcd_output(menu, 1, "Unknown error");
break;
}
if (button == BUTTON_SHORT_RELEASED)
menu_entry_dropback(menu, my_parent);
return;
} else if (currently_selected < loaded) {
/* Show currently selected profile */
menu_lcd_outputf(menu, 1, "%s", &profile_list[currently_selected][0]);
if (button == BUTTON_SHORT_RELEASED) {
/* Execute selected profile */
profile_ret_val = temp_profile_executer_start(&profile_list[currently_selected][0]);
if (profile_ret_val == PL_RET_SUCCESS) {
menu_entry_enter(menu, gui_menu_temp_profile_execute, true);
return;
}
}
if (delta >= 4) {
menu_ack_rotary_delta(menu);
if (currently_selected < (loaded - 1))
currently_selected++;
} else if (delta <= -4) {
menu_ack_rotary_delta(menu);
if (currently_selected > 0)
currently_selected--;
}
}
}
}
static void gui_menu_constant_temperature_driver_setup(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent) static void gui_menu_constant_temperature_driver_setup(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent)
{ {
static void IN_SECTION(.ccm.bss) *my_parent; static void IN_SECTION(.ccm.bss) *my_parent;
@@ -412,6 +597,7 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr
bool menu_changed = false; bool menu_changed = false;
static const char * const root_entry_names[] = { static const char * const root_entry_names[] = {
"Constant Temp", "Constant Temp",
"Temp Profile",
"Monitoring", "Monitoring",
"Error Flags", "Error Flags",
"About", "About",
@@ -419,6 +605,7 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr
}; };
static const menu_func_t root_entry_funcs[] = { static const menu_func_t root_entry_funcs[] = {
gui_menu_constant_temperature_driver_setup, gui_menu_constant_temperature_driver_setup,
gui_menu_temp_profile_select,
gui_menu_monitor, gui_menu_monitor,
gui_menu_err_flags, gui_menu_err_flags,
gui_menu_about, gui_menu_about,

View File

@@ -273,3 +273,10 @@ void menu_display_clear(struct lcd_menu *menu)
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
menu->update_display(i, ""); menu->update_display(i, "");
} }
uint32_t menu_list_get_currently_selected(struct menu_list *list)
{
if (!list)
return 0;
return list->currently_selected;
}

View File

@@ -0,0 +1,46 @@
project(updater-ram-code)
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_CROSSCOMPILING 1)
cmake_minimum_required(VERSION 3.0)
set(CMAKE_TOOLCHAIN_FILE "arm-none-eabi-gcc.cmake")
set(ELFFILE ${PROJECT_NAME}.elf)
set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/ram-link.ld)
set(ELFFILE "${PROJECT_NAME}.elf")
aux_source_directory("." SRCS)
aux_source_directory("fatfs" FATFS_SRCS)
aux_source_directory("fatfs/shimatta_sdio_driver" SDIO_SRCS)
add_executable(${ELFFILE} ${SRCS} ${FATFS_SRCS} ${SDIO_SRCS})
target_include_directories(${ELFFILE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_options(${ELFFILE} PRIVATE -Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter)
target_compile_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare -Os -g3)
target_compile_definitions(${ELFFILE} PRIVATE -DBASE64_LOOKUP_TABLE_SECTION=\".ccm.bss\" -DSHELLMATTA_HELP_ALIAS=\"?\" -DGIT_VER=${GIT_DESCRIBE} -DHSE_VALUE=8000000UL -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4)
target_link_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles -T${LINKER_SCRIPT} -Wl,--print-memory-usage)
set(GEN_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/generated")
set(GEN_HEADER_FILE "${GEN_HEADER_PATH}/${PROJECT_NAME}.bin.h")
target_include_directories(${ELFFILE} INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/include/")
set(GEN_HEADER_FILE "${CMAKE_CURRENT_BINARY_DIR}/include/generated/${PROJECT_NAME}.bin.h")
add_custom_target(updater-ram-code-header-blob DEPENDS ${GEN_HEADER_FILE})
add_custom_command(DEPENDS
${ELFFILE}
OUTPUT
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.bin"
COMMAND
${CMAKE_OBJCOPY} -O binary ${ELFFILE} "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.bin"
)
add_custom_command(DEPENDS
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.bin"
OUTPUT
${GEN_HEADER_FILE}
COMMAND
mkdir -p ${GEN_HEADER_PATH} && python "${CMAKE_CURRENT_SOURCE_DIR}/bin2carray.py" "${GEN_HEADER_FILE}" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.bin"
)

View File

@@ -1,82 +0,0 @@
RAM_CODE_TARGET = updater-ram-code
target = $(RAM_CODE_TARGET)
OBJDIR = obj
CFILES = main.c startup.c hex-parser.c
CFILES += fatfs/ff.c fatfs/diskio.c fatfs/ffsystem.c fatfs/ffunicode.c fatfs/shimatta_sdio_driver/shimatta_sdio.c
LINKER_SCRIPT = ram-link.ld
MAPFILE = $(RAM_CODE_TARGET)
PREFIX = arm-none-eabi-
CC = $(PREFIX)gcc
OBJCOPY = $(PREFIX)objcopy
SIZE = $(PREFIX)size
ifneq ($(VERBOSE),true)
QUIET=@
else
QUIET=
endif
DEFINES = -DSTM32F407xx -DSTM32F4XX -DHSE_VALUE=8000000UL
INCLUDEPATH = -Iinclude
LFLAGS = -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
LFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles
LFLAGS += -T$(LINKER_SCRIPT) -Wl,-Map=$(MAPFILE).map -Wl,--print-memory-usage -g3
CFLAGS = -c -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -Os -g3
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles
CFLAGS += -Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter -Wimplicit-fallthrough=3 -Wsign-compare
OBJ = $(CFILES:%.c=$(OBJDIR)/%.c.o)
default: $(RAM_CODE_TARGET).bin.h
all: $(RAM_CODE_TARGET).bin.h
%.bin.h: %.bin
@echo "[BIN2H] $@"
$(QUIET)python bin2carray.py $@ $^
$(RAM_CODE_TARGET).bin: $(RAM_CODE_TARGET).elf
@echo "[ELF2BIN] $@"
$(QUIET)$(OBJCOPY) -O binary $^ $@
$(RAM_CODE_TARGET).elf: $(OBJ) $(LINKER_SCRIPT)
@echo [LD] $@
$(QUIET)$(CC) $(LFLAGS) $(LIBRARYPATH) -o $@ $(OBJ) $(ASOBJ) $(LIBRARIES)
$(QUIET)$(SIZE) $@
$(OBJ):
@echo [CC] $@
$(eval OUTPATH=$(dir $@))
@mkdir -p $(OUTPATH)
$(QUIET)$(CC) $(CFLAGS) -MMD -MT $@ $(INCLUDEPATH) $(DEFINES) -o $@ $(@:$(OBJDIR)/%.c.o=%.c)
.PHONY: clean qtproject
clean:
@echo [CLEAN]
$(QUIET)rm -f $(OBJ) $(MAPFILE).map $(CFILES:%.c=$(OBJDIR)/%.c.d) $(RAM_CODE_TARGET).bin $(RAM_CODE_TARGET).elf $(RAM_CODE_TARGET).bin.c
qtproject:
$(QUIET)rm -f $(target).files $(target).cflags $(target).config $(target).creator $(target).includes $(target).creator.user
@echo "Generating source file list"
$(QUIET)echo "$(CFILES)" | tr ' ' '\n' > $(target).files
@echo -n "Appending found header files from folders "
@echo `echo $(INCLUDEPATH) | sed "s/-I//g"`
$(QUIET)for dir in `echo $(INCLUDEPATH) | sed "s/-I//g"`; do \
find `echo "$${dir}"` -name "*.h" >> $(target).files; \
done
@echo "Generating $(target).cflags"
$(QUIET)echo "" > $(target).cflags
@echo "Generating $(target).includes"
$(QUIET)echo $(INCLUDEPATH) | sed "s/-I/,/g" | tr , '\n' | sed "/^$$/d" > $(target).includes;
@echo "Generating $(target).config"
$(QUIET)echo $(DEFINES) | sed "s/-D/,#define /g" | tr , '\n' | sed "/^$$/d" > $(target).config
@echo "Generating $(target).creator"
$(QUIET)echo "[GENERAL]" > $(target).creator
-include $(CFILES:%.c=$(OBJDIR)/%.c.d)

View File

@@ -4,6 +4,7 @@
# bin2carray <output file> <input file> # bin2carray <output file> <input file>
import os import os
import os.path
import sys import sys
if len(sys.argv) < 3: if len(sys.argv) < 3:
@@ -18,7 +19,7 @@ with open(source_file, "rb") as src:
data = src.read() data = src.read()
with open(dest_file, "w") as dest: with open(dest_file, "w") as dest:
header_guard = "__" + dest_file.replace('.', '_').replace('-', '_') + "_H__" header_guard = "__" + os.path.basename(dest_file).replace('.', '_').replace('-', '_') + "_H__"
dest.write("#ifndef %s\n" % (header_guard)) dest.write("#ifndef %s\n" % (header_guard))
dest.write("#define %s\n" % (header_guard)) dest.write("#define %s\n" % (header_guard))
dest.write("static const char binary_blob[%d] = {\n" % (len(data))) dest.write("static const char binary_blob[%d] = {\n" % (len(data)))

View File

@@ -20,7 +20,7 @@
#include <reflow-controller/updater/updater.h> #include <reflow-controller/updater/updater.h>
#include <reflow-controller/safety/watchdog.h> #include <reflow-controller/safety/watchdog.h>
#include "ram-code/updater-ram-code.bin.h" #include <generated/updater-ram-code.bin.h>
#include <stm32/stm32f4xx.h> #include <stm32/stm32f4xx.h>
#include <cmsis/core_cm4.h> #include <cmsis/core_cm4.h>
#include <stdint.h> #include <stdint.h>