diff --git a/c-style-checker b/c-style-checker index cb93726..aeb2707 160000 --- a/c-style-checker +++ b/c-style-checker @@ -1 +1 @@ -Subproject commit cb937262aa71ee3d610900d7f14eef28e9f11dd0 +Subproject commit aeb2707d80049094337742d0f62cd24dbef1c01d diff --git a/stm-firmware/.gitignore b/stm-firmware/.gitignore index bcb7a46..3258d04 100644 --- a/stm-firmware/.gitignore +++ b/stm-firmware/.gitignore @@ -16,3 +16,10 @@ reflow-controller.includes *.files *.user.* *.user + +# VSCODE and CLANGD sepcific excludes + +.vscode/ +build/ +.cache/ +compile_commands.json diff --git a/stm-firmware/CMakeLists.txt b/stm-firmware/CMakeLists.txt index 6325d1d..1bb7ac2 100644 --- a/stm-firmware/CMakeLists.txt +++ b/stm-firmware/CMakeLists.txt @@ -1,7 +1,7 @@ set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_CROSSCOMPILING 1) -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.18) set(CMAKE_TOOLCHAIN_FILE "arm-none-eabi-gcc.cmake") @@ -38,31 +38,16 @@ if (GIT_FOUND) ) message("${BoldGreen}Git based version number: ${GIT_DESCRIBE}${ColorReset}") else (GIT_FOUND) - set(GIT_DESCRIBE "v0.0.0-unknown") message("${BoldRed}No git installation found. It is highly recommended using git to generate the version number") - message("Version is set to: ${GIT_DESCRIBE}${ColorReset}") + message(FATAL_ERROR "Git is required") endif (GIT_FOUND) -find_program(VIRTUALENV virtualenv) -if (VIRTUALENV) - message("Python virtual environment found") - execute_process( - COMMAND ${VIRTUALENV} venv - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - OUTPUT_QUIET - COMMAND_ERROR_IS_FATAL ANY - ) - set(VENV_BIN "${CMAKE_CURRENT_BINARY_DIR}/venv/bin") - execute_process( - COMMAND ./pip install -r "${CMAKE_CURRENT_SOURCE_DIR}/crc-patcher/requirements.txt" - WORKING_DIRECTORY ${VENV_BIN} - OUTPUT_QUIET - COMMAND_ERROR_IS_FATAL ANY - ) - message("${BoldGreen}python virtual environment set up!${ColorReset}") -else(VIRTUALENV) - message(FATAL_ERROR "${BoldRed}Python virtual environment not set up: virtualenv: command not found!${ColorReset}") -endif (VIRTUALENV) +find_program(PATCHELFCRC patchelfcrc) +if (PATCHELFCRC) + message("patchelfcrc found: ${PATCHELFCRC}") +else(PATCHELFCRC) + message(FATAL_ERROR "${BoldRed}Patchelfcrc not found. Cannot patch CRC checksum into ELF file: patchelfcrc: command not found! See: https://git.shimatta.de/mhu/patchelfcrc${ColorReset}") +endif (PATCHELFCRC) set(ELFFILE ${PROJECT_NAME}.elf) @@ -71,11 +56,10 @@ set(MAPFILE ${PROJECT_NAME}.map) 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) +add_compile_options(-mlittle-endian -mthumb -mcpu=cortex-m4 -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_definitions(-DBASE64_LOOKUP_TABLE_SECTION=\".ccm.bss\" -DSHELLMATTA_HELP_ALIAS=\"?\" -DHSE_VALUE=8000000UL -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4) add_subdirectory(doxygen) add_subdirectory(updater/ram-code) @@ -115,24 +99,35 @@ aux_source_directory("shellmatta/src" SHELLMATTA_SRCS) aux_source_directory("updater" UPDATER_SRCS) aux_source_directory("temp-profile" PROFILE_SRCS) +set(GEN_VERSION_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/generated-version") + + +add_custom_target( + generate-version-header + COMMAND mkdir -p ${GEN_VERSION_HEADER_PATH} && bash "${CMAKE_CURRENT_SOURCE_DIR}/create_version_header.sh" "${GEN_VERSION_HEADER_PATH}/version.h" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Generating version number using git" +) + 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} ${PROFILE_SRCS} ) -add_dependencies(${ELFFILE} updater-ram-code-header-blob) +add_dependencies(${ELFFILE} updater-ram-code-header-blob generate-version-header) + 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_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -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 linklist-lib) -target_include_directories(${ELFFILE} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/updater/ram-code/include/") +target_include_directories(${ELFFILE} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/updater/ram-code/include/" "${CMAKE_CURRENT_BINARY_DIR}/include/") add_custom_command( TARGET ${ELFFILE} POST_BUILD - COMMAND ./python "${CMAKE_CURRENT_SOURCE_DIR}/crc-patcher/crc-patch-elf.py" "${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}" - WORKING_DIRECTORY ${VENV_BIN} + COMMAND ${PATCHELFCRC} --little-endian --verbose --granularity word --start-magic 0xa8be53f9 --end-magic 0xffa582ff -O .flashcrc -p crc-32-mpeg -S .text -S .data -S .ccmdata -S .vectors "${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Running Flash CRC Patcher" ) diff --git a/stm-firmware/config-parser/config-parser.c b/stm-firmware/config-parser/config-parser.c index 1c01f17..2ec48e4 100644 --- a/stm-firmware/config-parser/config-parser.c +++ b/stm-firmware/config-parser/config-parser.c @@ -28,7 +28,14 @@ #include #include +/** + * @brief Config parser magic value used to check sanity of passed structs + */ #define CONFIG_PARSER_MAGIC 0x464a6e2bUL + +/** + * @brief Config parser type casting macro + */ #define CONFIG_PARSER(p) ((struct config_parser *)(p)) /** @@ -37,10 +44,11 @@ * If the pointer is invalid, the function using this macro will return with * CONFIG_PARSER_PARAM_ERR */ -#define config_parser_check_handle(handle) do { if (!(handle) || \ - ((struct config_parser *)(handle))->magic != CONFIG_PARSER_MAGIC) \ - return CONFIG_PARSER_PARAM_ERR; \ - } while (0) +#define config_parser_check_handle(handle) do { \ + if (!(handle) || \ + ((struct config_parser *)(handle))->magic != CONFIG_PARSER_MAGIC) \ + return CONFIG_PARSER_PARAM_ERR; \ + } while (0) config_parser_handle_t config_parser_open_file(struct config_parser *config_parser, bool write, const char *file_name, char *working_buffer, size_t buff_size) @@ -92,17 +100,17 @@ static int parse_value(struct config_parser_entry *entry, char *value_start_toke if (value_start_token[0] != '-') { /* Try parsing as ul */ entry->value.uint_val = strtoul(value_start_token, &endptr, 0); - if (endptr == value_start_token) { + if (endptr == value_start_token) return -1; - } + entry->type = CONFIG_PARSER_TYPE_UINT; goto exit; } else { /* Try parsing as int */ entry->value.int_val = strtod(value_start_token, &endptr); - if (endptr == value_start_token) { + if (endptr == value_start_token) return -1; - } + entry->type = CONFIG_PARSER_TYPE_INT; } @@ -110,14 +118,16 @@ exit: return 0; } -enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, struct config_parser_entry *entry, bool force_float) +enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, struct config_parser_entry *entry, + bool force_float) { struct config_parser *p; - config_parser_check_handle(handle); - p = CONFIG_PARSER(handle); char *token; int token_round = 0; + config_parser_check_handle(handle); + p = CONFIG_PARSER(handle); + if (!entry) return CONFIG_PARSER_PARAM_ERR; @@ -131,8 +141,7 @@ enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, str if (token[0] == '#') { if (token_round == 0) return CONFIG_PARSER_LINE_COMMENT; - else - break; + break; } switch (token_round) { @@ -140,9 +149,8 @@ enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, str entry->name = token; break; case 1: /* = Symbol */ - if (strcmp(token, "=")) { + if (strcmp(token, "=")) return CONFIG_PARSER_LINE_MALFORM; - } break; case 2: /* VALUE */ if (parse_value(entry, token)) @@ -172,6 +180,7 @@ enum config_parser_ret config_parser_reset_to_start(config_parser_handle_t handl { FRESULT res; struct config_parser *p; + config_parser_check_handle(handle); p = CONFIG_PARSER(handle); @@ -194,6 +203,7 @@ enum config_parser_ret config_parser_close_file(config_parser_handle_t handle) { struct config_parser *p; FRESULT res; + config_parser_check_handle(handle); p = CONFIG_PARSER(handle); diff --git a/stm-firmware/crc-patcher/crc-patch-elf.py b/stm-firmware/crc-patcher/crc-patch-elf.py deleted file mode 100755 index 64e3439..0000000 --- a/stm-firmware/crc-patcher/crc-patch-elf.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/bin/python - -""" -This script patches the CRC checksums into an existing ELF file. - -For this, it searches the follwoing sections: - 1) .text - 2) .data - 3) .ccmdata - 4) .vectors - -All sections MUST be a multiple of 4 bytes long because the CRC calculation relies on whole 32 bit words. -The sections are excrated and the CRC is calculated for each section. - -In the section .flashcrc, the script expects a single struct with the prototype: -struct flash_crcs { - uint32_t start_magic; - uint32_t crc_section_text; - uint32_t crc_section_data; - uint32_t crc_section_ccm_data; - uint32_t crc_section_vectors; - uint32_t end_magic; -}; - -It checks, if the start magic and end magic are set to the appropriate values and then patches in the CRC values of the sections. -The magic values checked for are: 0xA8BE53F9 and 0xFFA582FF -""" -from elftools.elf.elffile import ELFFile -from elftools.elf.segments import Segment -import elftools.elf.constants as elf_const -import sys -import crcmod -import crcmod.predefined -import struct - -crc_calc = crcmod.predefined.mkCrcFun('crc-32-mpeg') - -if len(sys.argv) < 2: - print("Usage:", sys.argv[0], ' ') - sys.exit(-1) - -filename=sys.argv[1] - -def section_calculate_crc(section): - data = bytearray(section.data()) - be_data = bytearray([0 for k in range(0, len(data))]) - # Rearrange data, because the STM controller sees it as 32 bit little endian words - for i in range(0, int(len(data)/4)): - be_data[i*4+0] = data[i*4+3] - be_data[i*4+1] = data[i*4+2] - be_data[i*4+2] = data[i*4+1] - be_data[i*4+3] = data[i*4+0] - - return crc_calc(be_data) - -with open(filename, 'r+b') as f: - elf = ELFFile(f) - sections = {} - sections['.text'] = elf.get_section_by_name('.text') - sections['.data'] = elf.get_section_by_name('.data') - sections['.ccmdata'] = elf.get_section_by_name('.ccmdata') - sections['.vectors'] = elf.get_section_by_name('.vectors') - - for key, sec in sections.items(): - if sec is None: - print("Error! Section", key, "not found in ELF file!") - sys.exit(-1) - print('Found section', key, 'Size:', - sec.data_size, 'Type:', sec['sh_type']) - if sec['sh_type'] != 'SHT_PROGBITS': - print('Error! Section must be of type SHT_PROGBITS') - sys.exit(-1) - if (sec.data_size % 4 != 0): - print("Section", key, "has wrong size. Must be a multiple of 4 bytes!") - sys.exit(-1) - - text_crc = section_calculate_crc(sections['.text']) - print('CRC of .text section:', hex(text_crc)) - data_crc = section_calculate_crc(sections['.data']) - print('CRC of .data section:', hex(data_crc)) - ccmdata_crc = section_calculate_crc(sections['.ccmdata']) - print('CRC of .ccmdata section:', hex(ccmdata_crc)) - vextors_crc = section_calculate_crc(sections['.vectors']) - print('CRC of .vectors section:', hex(vextors_crc)) - - # Check the flashcrc section - flashcrc_sec = elf.get_section_by_name('.flashcrc') - if flashcrc_sec is None: - print('Section for flash CRC missing!') - sys.exit(-1) - if flashcrc_sec.data_size != 6*4: - print("Error: .flashcrc section has wrong size:",flashcrc_sec.data_size) - sys.exit(-1); - - crc_sec_data = bytearray(flashcrc_sec.data()) - magic1 = struct.unpack(' +* Copyright (C) 2022 Mario Hüttel * * This file is part of the Reflow Oven Controller Project. * @@ -37,7 +37,7 @@ cpath = os.path.join(project_dir, sys.argv[1]+'.c') hfile = sys.argv[1]+'.h' hpath = os.path.join(module_include_dir, hfile) -h_define = '__'+hfile.replace('.', '_').replace('-', '_').replace('/', '_').upper()+'__' +h_define = '_'+hfile.replace('.', '_').replace('-', '_').replace('/', '_').upper()+'_' if os.path.exists(cpath) or os.path.exists(hpath): print("File already exists! Abort!") diff --git a/stm-firmware/create_version_header.sh b/stm-firmware/create_version_header.sh new file mode 100755 index 0000000..0f87882 --- /dev/null +++ b/stm-firmware/create_version_header.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +if [[ -z $1 ]]; then + # Exit with error in case no output file is specified + exit -1 +fi + +firmware_version=`git describe --tags --always --dirty` +commit=`git rev-parse HEAD` + +echo "#ifndef _VERSION_GENERATED_H_" > $1 +echo "#define _VERSION_GENERATED_H_" >> $1 +echo "#define GIT_VERSION_STRING \"$firmware_version\"" >> $1 +echo "#define GIT_FULL_COMMIT \"$commit\"" >> $1 +echo "#endif /* _VERSION_GENERATED_H_ */" >> $1 \ No newline at end of file diff --git a/stm-firmware/fatfs/ff.c b/stm-firmware/fatfs/ff.c index 4ed9ce2..38a11ce 100644 --- a/stm-firmware/fatfs/ff.c +++ b/stm-firmware/fatfs/ff.c @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem Module R0.14b / +/ FatFs - Generic FAT Filesystem Module R0.15 w/patch1 / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2021, ChaN, all right reserved. +/ Copyright (C) 2022, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -30,7 +30,7 @@ ---------------------------------------------------------------------------*/ -#if FF_DEFINED != 86631 /* Revision ID */ +#if FF_DEFINED != 80286 /* Revision ID */ #error Wrong include file (ff.h). #endif @@ -208,26 +208,26 @@ #define PTE_StLba 8 /* MBR PTE: Start in LBA */ #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ -#define GPTH_Sign 0 /* GPT: Header signature (8-byte) */ -#define GPTH_Rev 8 /* GPT: Revision (DWORD) */ -#define GPTH_Size 12 /* GPT: Header size (DWORD) */ -#define GPTH_Bcc 16 /* GPT: Header BCC (DWORD) */ -#define GPTH_CurLba 24 /* GPT: Main header LBA (QWORD) */ -#define GPTH_BakLba 32 /* GPT: Backup header LBA (QWORD) */ -#define GPTH_FstLba 40 /* GPT: First LBA for partitions (QWORD) */ -#define GPTH_LstLba 48 /* GPT: Last LBA for partitions (QWORD) */ -#define GPTH_DskGuid 56 /* GPT: Disk GUID (16-byte) */ -#define GPTH_PtOfs 72 /* GPT: Partation table LBA (QWORD) */ -#define GPTH_PtNum 80 /* GPT: Number of table entries (DWORD) */ -#define GPTH_PteSize 84 /* GPT: Size of table entry (DWORD) */ -#define GPTH_PtBcc 88 /* GPT: Partation table BCC (DWORD) */ -#define SZ_GPTE 128 /* GPT: Size of partition table entry */ +#define GPTH_Sign 0 /* GPT HDR: Signature (8-byte) */ +#define GPTH_Rev 8 /* GPT HDR: Revision (DWORD) */ +#define GPTH_Size 12 /* GPT HDR: Header size (DWORD) */ +#define GPTH_Bcc 16 /* GPT HDR: Header BCC (DWORD) */ +#define GPTH_CurLba 24 /* GPT HDR: This header LBA (QWORD) */ +#define GPTH_BakLba 32 /* GPT HDR: Another header LBA (QWORD) */ +#define GPTH_FstLba 40 /* GPT HDR: First LBA for partition data (QWORD) */ +#define GPTH_LstLba 48 /* GPT HDR: Last LBA for partition data (QWORD) */ +#define GPTH_DskGuid 56 /* GPT HDR: Disk GUID (16-byte) */ +#define GPTH_PtOfs 72 /* GPT HDR: Partition table LBA (QWORD) */ +#define GPTH_PtNum 80 /* GPT HDR: Number of table entries (DWORD) */ +#define GPTH_PteSize 84 /* GPT HDR: Size of table entry (DWORD) */ +#define GPTH_PtBcc 88 /* GPT HDR: Partition table BCC (DWORD) */ +#define SZ_GPTE 128 /* GPT PTE: Size of partition table entry */ #define GPTE_PtGuid 0 /* GPT PTE: Partition type GUID (16-byte) */ #define GPTE_UpGuid 16 /* GPT PTE: Partition unique GUID (16-byte) */ -#define GPTE_FstLba 32 /* GPT PTE: First LBA (QWORD) */ -#define GPTE_LstLba 40 /* GPT PTE: Last LBA inclusive (QWORD) */ -#define GPTE_Flags 48 /* GPT PTE: Flags (QWORD) */ -#define GPTE_Name 56 /* GPT PTE: Name */ +#define GPTE_FstLba 32 /* GPT PTE: First LBA of partition (QWORD) */ +#define GPTE_LstLba 40 /* GPT PTE: Last LBA of partition (QWORD) */ +#define GPTE_Flags 48 /* GPT PTE: Partition flags (QWORD) */ +#define GPTE_Name 56 /* GPT PTE: Partition name */ /* Post process on fatal error in the file operations */ @@ -239,7 +239,7 @@ #if FF_USE_LFN == 1 #error Static LFN work area cannot be used in thread-safe configuration #endif -#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#define LEAVE_FF(fs, res) { unlock_volume(fs, res); return res; } #else #define LEAVE_FF(fs, res) return res #endif @@ -278,15 +278,15 @@ /* File lock controls */ -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK #if FF_FS_READONLY #error FF_FS_LOCK must be 0 at read-only configuration #endif typedef struct { - FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ + FATFS* fs; /* Object ID 1, volume (NULL:blank entry) */ DWORD clu; /* Object ID 2, containing directory (0:root) */ DWORD ofs; /* Object ID 3, offset in the directory */ - WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ + UINT ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ } FILESEM; #endif @@ -461,20 +461,23 @@ typedef struct { #if FF_VOLUMES < 1 || FF_VOLUMES > 10 #error Wrong FF_VOLUMES setting #endif -static FATFS* FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ +static FATFS *FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ static WORD Fsid; /* Filesystem mount ID */ #if FF_FS_RPATH != 0 -static BYTE CurrVol; /* Current drive */ +static BYTE CurrVol; /* Current drive set by f_chdrive() */ #endif #if FF_FS_LOCK != 0 static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ +#if FF_FS_REENTRANT +static BYTE SysLock; /* System lock flag (0:no mutex, 1:unlocked, 2:locked) */ +#endif #endif #if FF_STR_VOLUME_ID #ifdef FF_VOLUME_STRS -static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ +static const char *const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ #endif #endif @@ -563,7 +566,8 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #if FF_CODE_PAGE == 0 /* Run-time code page configuration */ #define CODEPAGE CodePage static WORD CodePage; /* Current code page */ -static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ +static const BYTE* ExCvt; /* Ptr to SBCS up-case table Ct???[] (null:not used) */ +static const BYTE* DbcTbl; /* Ptr to DBCS code range table Dc???[] (null:not used) */ static const BYTE Ct437[] = TBL_CT437; static const BYTE Ct720[] = TBL_CT720; @@ -887,21 +891,45 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ -static int lock_fs ( /* 1:Ok, 0:timeout */ - FATFS* fs /* Filesystem object */ + +static int lock_volume ( /* 1:Ok, 0:timeout */ + FATFS* fs, /* Filesystem object to lock */ + int syslock /* System lock required */ ) { - return ff_req_grant(fs->sobj); + int rv; + + +#if FF_FS_LOCK + rv = ff_mutex_take(fs->ldrv); /* Lock the volume */ + if (rv && syslock) { /* System lock reqiered? */ + rv = ff_mutex_take(FF_VOLUMES); /* Lock the system */ + if (rv) { + SysLock = 2; /* System lock succeeded */ + } else { + ff_mutex_give(fs->ldrv); /* Failed system lock */ + } + } +#else + rv = syslock ? ff_mutex_take(fs->ldrv) : ff_mutex_take(fs->ldrv); /* Lock the volume (this is to prevent compiler warning) */ +#endif + return rv; } -static void unlock_fs ( +static void unlock_volume ( FATFS* fs, /* Filesystem object */ FRESULT res /* Result code to be returned */ ) { if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { - ff_rel_grant(fs->sobj); +#if FF_FS_LOCK + if (SysLock == 2) { /* Is the system locked? */ + SysLock = 1; + ff_mutex_give(FF_VOLUMES); + } +#endif + ff_mutex_give(fs->ldrv); /* Unlock the volume */ } } @@ -909,12 +937,12 @@ static void unlock_fs ( -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK /*-----------------------------------------------------------------------*/ -/* File lock control functions */ +/* File shareing control functions */ /*-----------------------------------------------------------------------*/ -static FRESULT chk_lock ( /* Check if the file can be accessed */ +static FRESULT chk_share ( /* Check if the file can be accessed */ DIR* dp, /* Directory object pointing the file to be checked */ int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ ) @@ -941,16 +969,16 @@ static FRESULT chk_lock ( /* Check if the file can be accessed */ } -static int enq_lock (void) /* Check if an entry is available for a new object */ +static int enq_share (void) /* Check if an entry is available for a new object */ { UINT i; - for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; /* Find a free entry */ return (i == FF_FS_LOCK) ? 0 : 1; } -static UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ +static UINT inc_share ( /* Increment object open counter and returns its index (0:Internal error) */ DIR* dp, /* Directory object pointing the file to register or increment */ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ ) @@ -965,7 +993,7 @@ static UINT inc_lock ( /* Increment object open counter and returns its index (0 } if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ - for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; /* Find a free entry */ if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ Files[i].fs = dp->obj.fs; Files[i].clu = dp->obj.sclust; @@ -981,30 +1009,32 @@ static UINT inc_lock ( /* Increment object open counter and returns its index (0 } -static FRESULT dec_lock ( /* Decrement object open counter */ +static FRESULT dec_share ( /* Decrement object open counter */ UINT i /* Semaphore index (1..) */ ) { - WORD n; + UINT n; FRESULT res; if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ n = Files[i].ctr; - if (n == 0x100) n = 0; /* If write mode open, delete the entry */ + if (n == 0x100) n = 0; /* If write mode open, delete the object semaphore */ if (n > 0) n--; /* Decrement read mode open count */ Files[i].ctr = n; - if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ + if (n == 0) { /* Delete the object semaphore if open count becomes zero */ + Files[i].fs = 0; /* Free the entry << 1, there is a potential error in this process >>> */ + } res = FR_OK; } else { - res = FR_INT_ERR; /* Invalid index nunber */ + res = FR_INT_ERR; /* Invalid index number */ } return res; } -static void clear_lock ( /* Clear lock entries of the volume */ - FATFS *fs +static void clear_share ( /* Clear all lock entries of the volume */ + FATFS* fs ) { UINT i; @@ -1014,7 +1044,7 @@ static void clear_lock ( /* Clear lock entries of the volume */ } } -#endif /* FF_FS_LOCK != 0 */ +#endif /* FF_FS_LOCK */ @@ -1599,7 +1629,8 @@ static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FSIZE_t ofs /* File offset to be converted to cluster# */ ) { - DWORD cl, ncl, *tbl; + DWORD cl, ncl; + DWORD *tbl; FATFS *fs = fp->obj.fs; @@ -1990,7 +2021,7 @@ static void gen_numname ( seq = (UINT)sreg; } - /* Make suffix (~ + hexdecimal) */ + /* Make suffix (~ + hexadecimal) */ i = 7; do { c = (BYTE)((seq % 16) + '0'); seq /= 16; @@ -2092,17 +2123,17 @@ static DWORD xsum32 ( /* Returns 32-bit checksum */ -/*-----------------------------------*/ -/* exFAT: Get a directry entry block */ -/*-----------------------------------*/ +/*------------------------------------*/ +/* exFAT: Get a directory entry block */ +/*------------------------------------*/ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ - DIR* dp /* Reading direcotry object pointing top of the entry block to load */ + DIR* dp /* Reading directory object pointing top of the entry block to load */ ) { FRESULT res; UINT i, sz_ent; - BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory directory entry block 85+C0+C1s */ /* Load file directory entry */ @@ -2166,7 +2197,7 @@ static void init_alloc_info ( /*------------------------------------------------*/ static FRESULT load_obj_xdir ( - DIR* dp, /* Blank directory object to be used to access containing direcotry */ + DIR* dp, /* Blank directory object to be used to access containing directory */ const FFOBJID* obj /* Object with its containing directory information */ ) { @@ -2195,18 +2226,18 @@ static FRESULT load_obj_xdir ( /*----------------------------------------*/ static FRESULT store_xdir ( - DIR* dp /* Pointer to the direcotry object */ + DIR* dp /* Pointer to the directory object */ ) { FRESULT res; UINT nent; - BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the directory entry block 85+C0+C1s */ /* Create set sum */ st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); nent = dirb[XDIR_NumSec] + 1; - /* Store the direcotry entry block to the directory */ + /* Store the directory entry block to the directory */ res = dir_sdi(dp, dp->blk_ofs); while (res == FR_OK) { res = move_window(dp->obj.fs, dp->sect); @@ -2223,11 +2254,11 @@ static FRESULT store_xdir ( /*-------------------------------------------*/ -/* exFAT: Create a new directory enrty block */ +/* exFAT: Create a new directory entry block */ /*-------------------------------------------*/ static void create_xdir ( - BYTE* dirb, /* Pointer to the direcotry entry block buffer */ + BYTE* dirb, /* Pointer to the directory entry block buffer */ const WCHAR* lfn /* Pointer to the object name */ ) { @@ -2610,19 +2641,23 @@ static void get_fileinfo ( si = SZDIRE * 2; di = 0; /* 1st C1 entry in the entry block */ hs = 0; while (nc < fs->dirbuf[XDIR_NumName]) { - if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + if (si >= MAXDIRB(FF_MAX_LFN)) { /* Truncated directory block? */ + di = 0; break; + } + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ wc = ld_word(fs->dirbuf + si); si += 2; nc++; /* Get a character */ - if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ - hs = wc; continue; /* Get low surrogate */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ } nw = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Buffer overflow or wrong char? */ + if (nw == 0) { /* Buffer overflow or wrong char? */ + di = 0; break; + } di += nw; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ - if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ + if (di == 0) fno->fname[di++] = '\?'; /* Inaccessible object name? */ fno->fname[di] = 0; /* Terminate the name */ fno->altname[0] = 0; /* exFAT does not support SFN */ @@ -2643,7 +2678,9 @@ static void get_fileinfo ( hs = wc; continue; /* Get low surrogate */ } nw = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Buffer overflow or wrong char? */ + if (nw == 0) { /* Buffer overflow or wrong char? */ + di = 0; break; + } di += nw; hs = 0; } @@ -2663,9 +2700,13 @@ static void get_fileinfo ( wc = wc << 8 | dp->dir[si++]; } wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ - if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ + if (wc == 0) { /* Wrong char in the current code page? */ + di = 0; break; + } nw = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Buffer overflow? */ + if (nw == 0) { /* Buffer overflow? */ + di = 0; break; + } di += nw; #else /* ANSI/OEM output */ fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ @@ -2674,8 +2715,8 @@ static void get_fileinfo ( fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ - if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ - fno->fname[di++] = '?'; + if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccessible */ + fno->fname[di++] = '\?'; } else { for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ wc = (WCHAR)fno->altname[si]; @@ -2756,7 +2797,8 @@ static int pattern_match ( /* 0:mismatched, 1:matched */ UINT recur /* Recursion count */ ) { - const TCHAR *pptr, *nptr; + const TCHAR *pptr; + const TCHAR *nptr; DWORD pchr, nchr; UINT sk; @@ -2770,12 +2812,16 @@ static int pattern_match ( /* 0:mismatched, 1:matched */ do { pptr = pat; nptr = nam; /* Top of pattern and name to match */ for (;;) { - if (*pptr == '?' || *pptr == '*') { /* Wildcard term? */ + if (*pptr == '\?' || *pptr == '*') { /* Wildcard term? */ if (recur == 0) return 0; /* Too many wildcard terms? */ sk = 0; do { /* Analyze the wildcard term */ - if (*pptr++ == '?') sk++; else sk |= 0x100; - } while (*pptr == '?' || *pptr == '*'); + if (*pptr++ == '\?') { + sk++; + } else { + sk |= 0x100; + } + } while (*pptr == '\?' || *pptr == '*'); if (pattern_match(pptr, nptr, sk, recur - 1)) return 1; /* Test new branch (recursive call) */ nchr = *nptr; break; /* Branch mismatched */ } @@ -2805,10 +2851,11 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr { #if FF_USE_LFN /* LFN configuration */ BYTE b, cf; - WCHAR wc, *lfn; + WCHAR wc; + WCHAR *lfn; + const TCHAR* p; DWORD uc; UINT i, ni, si, di; - const TCHAR *p; /* Create LFN into LFN working buffer */ @@ -2930,7 +2977,8 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr #else /* FF_USE_LFN : Non-LFN configuration */ - BYTE c, d, *sfn; + BYTE c, d; + BYTE *sfn; UINT ni, si, i; const char *p; @@ -3091,7 +3139,8 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb const TCHAR** path /* Pointer to pointer to the path name */ ) { - const TCHAR *tp, *tt; + const TCHAR *tp; + const TCHAR *tt; TCHAR tc; int i; int vol = -1; @@ -3102,7 +3151,9 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb tt = tp = *path; if (!tp) return vol; /* Invalid path name? */ - do tc = *tt++; while (!IsTerminator(tc) && tc != ':'); /* Find a colon in the path */ + do { /* Find a colon in the path */ + tc = *tt++; + } while (!IsTerminator(tc) && tc != ':'); if (tc == ':') { /* DOS/Windows style volume ID? */ i = FF_VOLUMES; @@ -3190,16 +3241,18 @@ static int test_gpt_header ( /* 0:Invalid, 1:Valid */ ) { UINT i; - DWORD bcc; + DWORD bcc, hlen; - if (memcmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16)) return 0; /* Check sign, version (1.0) and length (92) */ - for (i = 0, bcc = 0xFFFFFFFF; i < 92; i++) { /* Check header BCC */ + if (memcmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1", 12)) return 0; /* Check signature and version (1.0) */ + hlen = ld_dword(gpth + GPTH_Size); /* Check header size */ + if (hlen < 92 || hlen > FF_MIN_SS) return 0; + for (i = 0, bcc = 0xFFFFFFFF; i < hlen; i++) { /* Check header BCC */ bcc = crc32(bcc, i - GPTH_Bcc < 4 ? 0 : gpth[i]); } if (~bcc != ld_dword(gpth + GPTH_Bcc)) return 0; if (ld_dword(gpth + GPTH_PteSize) != SZ_GPTE) return 0; /* Table entry size (must be SZ_GPTE bytes) */ - if (ld_dword(gpth + GPTH_PtNum) > 128) return 0; /* Table size (must be 128 entries or less) */ + if (ld_dword(gpth + GPTH_PtNum) > 128) return 0; /* Table size (must be 128 entries or less) */ return 1; } @@ -3209,7 +3262,7 @@ static int test_gpt_header ( /* 0:Invalid, 1:Valid */ /* Generate random value */ static DWORD make_rand ( DWORD seed, /* Seed value */ - BYTE* buff, /* Output buffer */ + BYTE *buff, /* Output buffer */ UINT n /* Data length */ ) { @@ -3277,7 +3330,7 @@ static UINT check_fs ( /* 0:FAT/FAT32 VBR, 1:exFAT VBR, 2:Not FAT and valid BS, static UINT find_volume ( /* Returns BS status found in the hosting drive */ FATFS* fs, /* Filesystem object */ - UINT part /* Partition to fined = 0:auto, 1..:forced */ + UINT part /* Partition to fined = 0:find as SFD and partitions, >0:forced partition number */ ) { UINT fmt, i; @@ -3332,15 +3385,15 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ FATFS** rfs, /* Pointer to pointer to the found filesystem object */ - BYTE mode /* !=0: Check write protection for write access */ + BYTE mode /* Desiered access mode to check write protection */ ) { int vol; + FATFS *fs; DSTATUS stat; LBA_t bsect; DWORD tsect, sysect, fasize, nclst, szbfat; WORD nrsv; - FATFS *fs; UINT fmt; @@ -3353,7 +3406,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs = FatFs[vol]; /* Get pointer to the filesystem object */ if (!fs) return FR_NOT_ENABLED; /* Is the filesystem object available? */ #if FF_FS_REENTRANT - if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ + if (!lock_volume(fs, 1)) return FR_TIMEOUT; /* Lock the volume, and system if needed */ #endif *rfs = fs; /* Return pointer to the filesystem object */ @@ -3371,9 +3424,8 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ /* The filesystem object is not valid. */ /* Following code attempts to mount the volume. (find an FAT volume, analyze the BPB and initialize the filesystem object) */ - fs->fs_type = 0; /* Clear the filesystem object */ - fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ - stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ + fs->fs_type = 0; /* Invalidate the filesystem object */ + stat = disk_initialize(fs->pdrv); /* Initialize the volume hosting physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ } @@ -3385,11 +3437,11 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif - /* Find an FAT volume on the drive */ + /* Find an FAT volume on the hosting drive */ fmt = find_volume(fs, LD2PT(vol)); - if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ + if (fmt == 4) return FR_DISK_ERR; /* An error occurred in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ - bsect = fs->winsect; /* Volume offset */ + bsect = fs->winsect; /* Volume offset in the hosting physical drive */ /* An FAT volume is found (bsect). Following code initializes the filesystem object */ @@ -3426,7 +3478,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->volbase = bsect; fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); - if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ + if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */ fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); /* Get bitmap location and check if it is contiguous (implementation assumption) */ @@ -3447,7 +3499,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); if (cv == 0xFFFFFFFF) break; /* Last link? */ - if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented? */ + if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented bitmap? */ } #if !FF_FS_READONLY @@ -3534,7 +3586,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #endif /* !FF_FS_READONLY */ } - fs->fs_type = (BYTE)fmt;/* FAT sub-type */ + fs->fs_type = (BYTE)fmt;/* FAT sub-type (the filesystem object gets valid) */ fs->id = ++Fsid; /* Volume mount ID */ #if FF_USE_LFN == 1 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ @@ -3545,8 +3597,8 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #if FF_FS_RPATH != 0 fs->cdir = 0; /* Initialize current directory */ #endif -#if FF_FS_LOCK != 0 /* Clear file lock semaphores */ - clear_lock(fs); +#if FF_FS_LOCK /* Clear file lock semaphores */ + clear_share(fs); #endif return FR_OK; } @@ -3559,7 +3611,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ /*-----------------------------------------------------------------------*/ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ - FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */ + FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR structure, to check validity */ FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ ) { @@ -3568,22 +3620,22 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ #if FF_FS_REENTRANT - if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ - if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + if (lock_volume(obj->fs, 0)) { /* Take a grant to access the volume */ + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting phsical drive is kept initialized */ res = FR_OK; } else { - unlock_fs(obj->fs, FR_OK); + unlock_volume(obj->fs, FR_OK); /* Invalidated volume, abort to access */ } - } else { + } else { /* Could not take */ res = FR_TIMEOUT; } #else - if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting phsical drive is kept initialized */ res = FR_OK; } #endif } - *rfs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ + *rfs = (res == FR_OK) ? obj->fs : 0; /* Return corresponding filesystem object if it is valid */ return res; } @@ -3614,30 +3666,42 @@ FRESULT f_mount ( const TCHAR *rp = path; - /* Get logical drive number */ + /* Get volume ID (logical drive number) */ vol = get_ldnumber(&rp); if (vol < 0) return FR_INVALID_DRIVE; - cfs = FatFs[vol]; /* Pointer to fs object */ + cfs = FatFs[vol]; /* Pointer to the filesystem object of the volume */ - if (cfs) { -#if FF_FS_LOCK != 0 - clear_lock(cfs); + if (cfs) { /* Unregister current filesystem object if regsitered */ + FatFs[vol] = 0; +#if FF_FS_LOCK + clear_share(cfs); #endif -#if FF_FS_REENTRANT /* Discard sync object of the current volume */ - if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; +#if FF_FS_REENTRANT /* Discard mutex of the current volume */ + ff_mutex_delete(vol); #endif - cfs->fs_type = 0; /* Clear old fs object */ + cfs->fs_type = 0; /* Invalidate the filesystem object to be unregistered */ } - if (fs) { - fs->fs_type = 0; /* Clear new fs object */ -#if FF_FS_REENTRANT /* Create sync object for the new volume */ - if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; + if (fs) { /* Register new filesystem object */ + fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ +#if FF_FS_REENTRANT /* Create a volume mutex */ + fs->ldrv = (BYTE)vol; /* Owner volume ID */ + if (!ff_mutex_create(vol)) return FR_INT_ERR; +#if FF_FS_LOCK + if (SysLock == 0) { /* Create a system mutex if needed */ + if (!ff_mutex_create(FF_VOLUMES)) { + ff_mutex_delete(vol); + return FR_INT_ERR; + } + SysLock = 1; /* System mutex is ready */ + } #endif +#endif + fs->fs_type = 0; /* Invalidate the new filesystem object */ + FatFs[vol] = fs; /* Register new fs object */ } - FatFs[vol] = fs; /* Register new fs object */ - if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ + if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted in subsequent file functions */ res = mount_volume(&path, &fs, 0); /* Force mounted the volume */ LEAVE_FF(fs, res); @@ -3681,9 +3745,9 @@ FRESULT f_open ( if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; } -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK else { - res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ + res = chk_share(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ } #endif } @@ -3691,8 +3755,8 @@ FRESULT f_open ( if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ -#if FF_FS_LOCK != 0 - res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; +#if FF_FS_LOCK + res = enq_share() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif @@ -3761,8 +3825,8 @@ FRESULT f_open ( if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dj.dir; -#if FF_FS_LOCK != 0 - fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ +#if FF_FS_LOCK + fp->obj.lockid = inc_share(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ if (fp->obj.lockid == 0) res = FR_INT_ERR; #endif } @@ -3825,8 +3889,8 @@ FRESULT f_open ( #endif } } -#if FF_FS_LOCK != 0 - if (res != FR_OK) dec_lock(fp->obj.lockid); /* Decrement file open counter if seek failed */ +#if FF_FS_LOCK + if (res != FR_OK) dec_share(fp->obj.lockid); /* Decrement file open counter if seek failed */ #endif } #endif @@ -3921,7 +3985,7 @@ FRESULT f_read ( fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ } #endif fp->sect = sect; @@ -4163,14 +4227,14 @@ FRESULT f_close ( { res = validate(&fp->obj, &fs); /* Lock volume */ if (res == FR_OK) { -#if FF_FS_LOCK != 0 - res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ +#if FF_FS_LOCK + res = dec_share(fp->obj.lockid); /* Decrement file open counter */ if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ #else fp->obj.fs = 0; /* Invalidate file object */ #endif #if FF_FS_REENTRANT - unlock_fs(fs, FR_OK); /* Unlock volume */ + unlock_volume(fs, FR_OK); /* Unlock volume */ #endif } } @@ -4344,7 +4408,9 @@ FRESULT f_getcwd ( #endif /* Add current directory path */ if (res == FR_OK) { - do *tp++ = buff[i++]; while (i < len); /* Copy stacked path string */ + do { /* Copy stacked path string */ + *tp++ = buff[i++]; + } while (i < len); } } FREE_NAMBUF(); @@ -4551,7 +4617,7 @@ FRESULT f_opendir ( if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ + dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; dp->obj.c_ofs = dp->blk_ofs; init_alloc_info(fs, &dp->obj); /* Get object allocation info */ @@ -4567,10 +4633,10 @@ FRESULT f_opendir ( if (res == FR_OK) { dp->obj.id = fs->id; res = dir_sdi(dp, 0); /* Rewind directory */ -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK if (res == FR_OK) { if (dp->obj.sclust != 0) { - dp->obj.lockid = inc_lock(dp, 0); /* Lock the sub directory */ + dp->obj.lockid = inc_share(dp, 0); /* Lock the sub directory */ if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; } else { dp->obj.lockid = 0; /* Root directory need not to be locked */ @@ -4582,7 +4648,7 @@ FRESULT f_opendir ( FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } - if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function faild */ + if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function failed */ LEAVE_FF(fs, res); } @@ -4604,14 +4670,14 @@ FRESULT f_closedir ( res = validate(&dp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { -#if FF_FS_LOCK != 0 - if (dp->obj.lockid) res = dec_lock(dp->obj.lockid); /* Decrement sub-directory open counter */ +#if FF_FS_LOCK + if (dp->obj.lockid) res = dec_share(dp->obj.lockid); /* Decrement sub-directory open counter */ if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ #else dp->obj.fs = 0; /* Invalidate directory object */ #endif #if FF_FS_REENTRANT - unlock_fs(fs, FR_OK); /* Unlock volume */ + unlock_volume(fs, FR_OK); /* Unlock volume */ #endif } return res; @@ -4637,7 +4703,7 @@ FRESULT f_readdir ( res = validate(&dp->obj, &fs); /* Check validity of the directory object */ if (res == FR_OK) { if (!fno) { - res = dir_sdi(dp, 0); /* Rewind the directory object */ + res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { INIT_NAMBUF(fs); res = DIR_READ_FILE(dp); /* Read an item */ @@ -4775,8 +4841,12 @@ FRESULT f_getfree ( clst = 2; obj.fs = fs; do { stat = get_fat(&obj, clst); - if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } - if (stat == 1) { res = FR_INT_ERR; break; } + if (stat == 0xFFFFFFFF) { + res = FR_DISK_ERR; break; + } + if (stat == 1) { + res = FR_INT_ERR; break; + } if (stat == 0) nfree++; } while (++clst < fs->n_fatent); } else { @@ -4789,12 +4859,12 @@ FRESULT f_getfree ( sect = fs->bitbase; /* Bitmap sector */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of bits with zero in the bitmap */ - if (i == 0) { + if (i == 0) { /* New sector? */ res = move_window(fs, sect++); if (res != FR_OK) break; } - for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { - if (!(bm & 1)) nfree++; + for (b = 8, bm = ~fs->win[i]; b && clst; b--, clst--) { + nfree += bm & 1; bm >>= 1; } i = (i + 1) % SS(fs); @@ -4806,7 +4876,7 @@ FRESULT f_getfree ( sect = fs->fatbase; /* Top of the FAT */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of entries with zero in the FAT */ - if (i == 0) { + if (i == 0) { /* New sector? */ res = move_window(fs, sect++); if (res != FR_OK) break; } @@ -4894,9 +4964,9 @@ FRESULT f_unlink ( ) { FRESULT res; + FATFS *fs; DIR dj, sdj; DWORD dclst = 0; - FATFS *fs; #if FF_FS_EXFAT FFOBJID obj; #endif @@ -4912,8 +4982,8 @@ FRESULT f_unlink ( if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; /* Cannot remove dot entry */ } -#if FF_FS_LOCK != 0 - if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ +#if FF_FS_LOCK + if (res == FR_OK) res = chk_share(&dj, 2); /* Check if it is an open object */ #endif if (res == FR_OK) { /* The object is accessible */ if (dj.fn[NSFLAG] & NS_NONAME) { @@ -4988,9 +5058,9 @@ FRESULT f_mkdir ( ) { FRESULT res; + FATFS *fs; DIR dj; FFOBJID sobj; - FATFS *fs; DWORD dcl, pcl, tm; DEF_NAMBUF @@ -5073,8 +5143,8 @@ FRESULT f_rename ( ) { FRESULT res; - DIR djo, djn; FATFS *fs; + DIR djo, djn; BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; LBA_t sect; DEF_NAMBUF @@ -5087,9 +5157,9 @@ FRESULT f_rename ( INIT_NAMBUF(fs); res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK if (res == FR_OK) { - res = chk_lock(&djo, 2); + res = chk_share(&djo, 2); } #endif if (res == FR_OK) { /* Object to be renamed is found */ @@ -5184,8 +5254,8 @@ FRESULT f_chmod ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; DEF_NAMBUF @@ -5230,8 +5300,8 @@ FRESULT f_utime ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; DEF_NAMBUF @@ -5278,8 +5348,8 @@ FRESULT f_getlabel ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; UINT si, di; WCHAR wc; @@ -5304,7 +5374,9 @@ FRESULT f_getlabel ( hs = wc; continue; } nw = put_utf((DWORD)hs << 16 | wc, &label[di], 4); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Encode error? */ + if (nw == 0) { /* Encode error? */ + di = 0; break; + } di += nw; hs = 0; } @@ -5319,7 +5391,9 @@ FRESULT f_getlabel ( #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ - if (wc == 0) { di = 0; break; } /* Invalid char in current code page? */ + if (wc == 0) { /* Invalid char in current code page? */ + di = 0; break; + } di += put_utf(wc, &label[di], 4); /* Store it in Unicode */ #else /* ANSI/OEM output */ label[di++] = (TCHAR)wc; @@ -5373,8 +5447,8 @@ FRESULT f_setlabel ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; BYTE dirvn[22]; UINT di; WCHAR wc; @@ -5530,14 +5604,20 @@ FRESULT f_expand ( for (;;) { /* Find a contiguous cluster block */ n = get_fat(&fp->obj, clst); if (++clst >= fs->n_fatent) clst = 2; - if (n == 1) { res = FR_INT_ERR; break; } - if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (n == 1) { + res = FR_INT_ERR; break; + } + if (n == 0xFFFFFFFF) { + res = FR_DISK_ERR; break; + } if (n == 0) { /* Is it a free cluster? */ if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ } else { scl = clst; ncl = 0; /* Not a free cluster */ } - if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ + if (clst == stcl) { /* No contiguous cluster? */ + res = FR_DENIED; break; + } } if (res == FR_OK) { /* A contiguous free area is found */ if (opt) { /* Allocate it now */ @@ -5659,8 +5739,8 @@ FRESULT f_forward ( static FRESULT create_partition ( BYTE drv, /* Physical drive number */ const LBA_t plst[], /* Partition list */ - BYTE sys, /* System ID (for only MBR, temp setting) */ - BYTE* buf /* Working buffer for a sector */ + BYTE sys, /* System ID for each partition (for only MBR) */ + BYTE *buf /* Working buffer for a sector */ ) { UINT i, cy; @@ -5689,7 +5769,7 @@ static FRESULT create_partition ( rnd = (DWORD)sz_drv + GET_FATTIME(); /* Random seed */ align = GPT_ALIGN / ss; /* Partition alignment for GPT [sector] */ sz_ptbl = GPT_ITEMS * SZ_GPTE / ss; /* Size of partition table [sector] */ - top_bpt = sz_drv - sz_ptbl - 1; /* Backup partiiton table start sector */ + top_bpt = sz_drv - sz_ptbl - 1; /* Backup partition table start sector */ nxt_alloc = 2 + sz_ptbl; /* First allocatable sector */ sz_pool = top_bpt - nxt_alloc; /* Size of allocatable area */ bcc = 0xFFFFFFFF; sz_part = 1; @@ -5802,14 +5882,16 @@ static FRESULT create_partition ( FRESULT f_mkfs ( const TCHAR* path, /* Logical drive number */ const MKFS_PARM* opt, /* Format options */ - void* work, /* Pointer to working buffer (null: use heap memory) */ + void* work, /* Pointer to working buffer (null: use len bytes of heap memory) */ UINT len /* Size of working buffer [byte] */ ) { static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */ - BYTE fsopt, fsty, sys, *buf, *pte, pdrv, ipart; + BYTE fsopt, fsty, sys, pdrv, ipart; + BYTE *buf; + BYTE *pte; WORD ss; /* Sector size */ DWORD sz_buf, sz_blk, n_clst, pau, nsect, n, vsn; LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */ @@ -5818,30 +5900,33 @@ FRESULT f_mkfs ( UINT n_fat, n_root, i; /* Index, Number of FATs and Number of roor dir entries */ int vol; DSTATUS ds; - FRESULT fr; + FRESULT res; /* Check mounted drive and clear work area */ vol = get_ldnumber(&path); /* Get target logical drive */ if (vol < 0) return FR_INVALID_DRIVE; if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the fs object if mounted */ - pdrv = LD2PD(vol); /* Physical drive */ - ipart = LD2PT(vol); /* Partition (0:create as new, 1..:get from partition table) */ - if (!opt) opt = &defopt; /* Use default parameter if it is not given */ + pdrv = LD2PD(vol); /* Hosting physical drive */ + ipart = LD2PT(vol); /* Hosting partition (0:create as new, 1..:existing partition) */ - /* Get physical drive status (sz_drv, sz_blk, ss) */ + /* Initialize the hosting physical drive */ ds = disk_initialize(pdrv); if (ds & STA_NOINIT) return FR_NOT_READY; if (ds & STA_PROTECT) return FR_WRITE_PROTECTED; + + /* Get physical drive parameters (sz_drv, sz_blk and ss) */ + if (!opt) opt = &defopt; /* Use default parameter if it is not given */ sz_blk = opt->align; - if (sz_blk == 0 && disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK) sz_blk = 1; - if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; + if (sz_blk == 0) disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk); /* Block size from the paramter or lower layer */ + if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Use default if the block size is invalid */ #if FF_MAX_SS != FF_MIN_SS if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else ss = FF_MAX_SS; #endif + /* Options for FAT sub-type and FAT parameters */ fsopt = opt->fmt & (FM_ANY | FM_SFD); n_fat = (opt->n_fat >= 1 && opt->n_fat <= 2) ? opt->n_fat : 1; @@ -5957,7 +6042,7 @@ FRESULT f_mkfs ( sz_fat = (DWORD)((sz_vol / sz_au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~((LBA_t)sz_blk - 1); /* Align data area to the erase block boundary */ if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ - n_clst = (DWORD)(sz_vol - (b_data - b_vol)) / sz_au; /* Number of clusters */ + n_clst = (DWORD)((sz_vol - (b_data - b_vol)) / sz_au); /* Number of clusters */ if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ @@ -6258,32 +6343,30 @@ FRESULT f_mkfs ( /* Determine system ID in the MBR partition table */ if (FF_FS_EXFAT && fsty == FS_EXFAT) { - sys = 0x07; /* exFAT */ + sys = 0x07; /* exFAT */ + } else if (fsty == FS_FAT32) { + sys = 0x0C; /* FAT32X */ + } else if (sz_vol >= 0x10000) { + sys = 0x06; /* FAT12/16 (large) */ + } else if (fsty == FS_FAT16) { + sys = 0x04; /* FAT16 */ } else { - if (fsty == FS_FAT32) { - sys = 0x0C; /* FAT32X */ - } else { - if (sz_vol >= 0x10000) { - sys = 0x06; /* FAT12/16 (large) */ - } else { - sys = (fsty == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ - } - } + sys = 0x01; /* FAT12 */ } /* Update partition information */ if (FF_MULTI_PARTITION && ipart != 0) { /* Volume is in the existing partition */ - if (!FF_LBA64 || !(fsopt & 0x80)) { + if (!FF_LBA64 || !(fsopt & 0x80)) { /* Is the partition in MBR? */ /* Update system ID in the partition table */ if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ buf[MBR_Table + (ipart - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ } } else { /* Volume as a new single partition */ - if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD */ + if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD format */ lba[0] = sz_vol; lba[1] = 0; - fr = create_partition(pdrv, lba, sys, buf); - if (fr != FR_OK) LEAVE_MKFS(fr); + res = create_partition(pdrv, lba, sys, buf); + if (res != FR_OK) LEAVE_MKFS(res); } } @@ -6308,17 +6391,22 @@ FRESULT f_fdisk ( { BYTE *buf = (BYTE*)work; DSTATUS stat; + FRESULT res; + /* Initialize the physical drive */ stat = disk_initialize(pdrv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + #if FF_USE_LFN == 3 if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ #endif if (!buf) return FR_NOT_ENOUGH_CORE; - LEAVE_MKFS(create_partition(pdrv, ptbl, 0x07, buf)); + res = create_partition(pdrv, ptbl, 0x07, buf); /* Create partitions (system ID is temporary setting and determined by f_mkfs) */ + + LEAVE_MKFS(res); } #endif /* FF_MULTI_PARTITION */ @@ -6388,9 +6476,15 @@ TCHAR* f_gets ( dc = s[0]; if (dc >= 0x80) { /* Multi-byte sequence? */ ct = 0; - if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } /* 2-byte sequence? */ - if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } /* 3-byte sequence? */ - if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } /* 4-byte sequence? */ + if ((dc & 0xE0) == 0xC0) { /* 2-byte sequence? */ + dc &= 0x1F; ct = 1; + } + if ((dc & 0xF0) == 0xE0) { /* 3-byte sequence? */ + dc &= 0x0F; ct = 2; + } + if ((dc & 0xF8) == 0xF0) { /* 4-byte sequence? */ + dc &= 0x07; ct = 3; + } if (ct == 0) continue; f_read(fp, s, ct, &rc); /* Get trailing bytes */ if (rc != ct) break; @@ -6417,25 +6511,21 @@ TCHAR* f_gets ( *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ - } else { - if (dc < 0x800) { /* 2-byte sequence? */ - *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 2; - } else { - if (dc < 0x10000) { /* 3-byte sequence? */ - *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); - *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 3; - } else { /* 4-byte sequence? */ - *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); - *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 4; - } - } + } else if (dc < 0x800) { /* 2-byte sequence? */ + *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 2; + } else if (dc < 0x10000) { /* 3-byte sequence? */ + *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); + *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 3; + } else { /* 4-byte sequence */ + *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); + *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 4; } #endif } @@ -6493,7 +6583,7 @@ static void putc_bfd (putbuff* pb, TCHAR c) WCHAR hs, wc; #if FF_LFN_UNICODE == 2 DWORD dc; - const TCHAR *tp; + const TCHAR* tp; #endif #endif @@ -6507,39 +6597,39 @@ static void putc_bfd (putbuff* pb, TCHAR c) #if FF_USE_LFN && FF_LFN_UNICODE #if FF_LFN_UNICODE == 1 /* UTF-16 input */ - if (IsSurrogateH(c)) { /* High surrogate? */ + if (IsSurrogateH(c)) { /* Is this a high-surrogate? */ pb->hs = c; return; /* Save it for next */ } hs = pb->hs; pb->hs = 0; - if (hs != 0) { /* There is a leading high surrogate */ - if (!IsSurrogateL(c)) hs = 0; /* Discard high surrogate if not a surrogate pair */ + if (hs != 0) { /* Is there a leading high-surrogate? */ + if (!IsSurrogateL(c)) hs = 0; /* Discard high-surrogate if not a surrogate pair */ } else { - if (IsSurrogateL(c)) return; /* Discard stray low surrogate */ + if (IsSurrogateL(c)) return; /* Discard stray low-surrogate */ } wc = c; #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ for (;;) { if (pb->ct == 0) { /* Out of multi-byte sequence? */ pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ - if ((BYTE)c < 0x80) break; /* Single byte? */ + if ((BYTE)c < 0x80) break; /* Single byte code? */ if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte sequence? */ if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte sequence? */ - if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte sequence? */ - return; + if (((BYTE)c & 0xF8) == 0xF0) pb->ct = 3; /* 4-byte sequence? */ + return; /* Wrong leading byte (discard it) */ } else { /* In the multi-byte sequence */ if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ - pb->ct = 0; continue; + pb->ct = 0; continue; /* Discard the sequense */ } pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ - if (--pb->ct == 0) break; /* End of multi-byte sequence? */ + if (--pb->ct == 0) break; /* End of the sequence? */ return; } } tp = (const TCHAR*)pb->bs; - dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ + dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ if (dc == 0xFFFFFFFF) return; /* Wrong code? */ - wc = (WCHAR)dc; hs = (WCHAR)(dc >> 16); + wc = (WCHAR)dc; #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ if (IsSurrogate(c) || c >= 0x110000) return; /* Discard invalid code */ if (c >= 0x10000) { /* Out of BMP? */ @@ -6742,7 +6832,7 @@ static void ftoa ( er = "NaN"; } else { if (prec < 0) prec = 6; /* Default precision? (6 fractional digits) */ - if (val < 0) { /* Nagative? */ + if (val < 0) { /* Negative? */ val = 0 - val; sign = '-'; } else { sign = '+'; @@ -6790,7 +6880,9 @@ static void ftoa ( } if (er) { /* Error condition */ if (sign) *buf++ = sign; /* Add sign if needed */ - do *buf++ = *er++; while (*er); /* Put error symbol */ + do { /* Put error symbol */ + *buf++ = *er++; + } while (*er); } *buf = 0; /* Term */ } @@ -6813,7 +6905,8 @@ int f_printf ( #else DWORD v; #endif - TCHAR tc, pad, *tp; + TCHAR *tp; + TCHAR tc, pad; TCHAR nul = 0; char d, str[SZ_NUM_BUF]; @@ -6870,17 +6963,22 @@ int f_printf ( switch (tc) { /* Atgument type is... */ case 'b': /* Unsigned binary */ r = 2; break; + case 'o': /* Unsigned octal */ r = 8; break; + case 'd': /* Signed decimal */ - case 'u': /* Unsigned decimal */ + case 'u': /* Unsigned decimal */ r = 10; break; - case 'x': /* Unsigned hexdecimal (lower case) */ - case 'X': /* Unsigned hexdecimal (upper case) */ + + case 'x': /* Unsigned hexadecimal (lower case) */ + case 'X': /* Unsigned hexadecimal (upper case) */ r = 16; break; + case 'c': /* Character */ putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; + case 's': /* String */ tp = va_arg(arp, TCHAR*); /* Get a pointer argument */ if (!tp) tp = &nul; /* Null ptr generates a null string */ @@ -6894,7 +6992,7 @@ int f_printf ( case 'f': /* Floating point (decimal) */ case 'e': /* Floating point (e) */ case 'E': /* Floating point (E) */ - ftoa(str, va_arg(arp, double), prec, tc); /* Make a flaoting point string */ + ftoa(str, va_arg(arp, double), prec, tc); /* Make a floating point string */ for (j = strlen(str); !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ for (i = 0; str[i]; putc_bfd(&pb, str[i++])) ; /* Body */ while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ @@ -6906,14 +7004,12 @@ int f_printf ( /* Get an integer argument and put it in numeral */ #if FF_PRINT_LLI && FF_INTDEF == 2 - if (f & 8) { /* long long argument? */ - v = (QWORD)va_arg(arp, LONGLONG); - } else { - if (f & 4) { /* long argument? */ - v = (tc == 'd') ? (QWORD)(LONGLONG)va_arg(arp, long) : (QWORD)va_arg(arp, unsigned long); - } else { /* int/short/char argument */ - v = (tc == 'd') ? (QWORD)(LONGLONG)va_arg(arp, int) : (QWORD)va_arg(arp, unsigned int); - } + if (f & 8) { /* long long argument? */ + v = (QWORD)va_arg(arp, long long); + } else if (f & 4) { /* long argument? */ + v = (tc == 'd') ? (QWORD)(long long)va_arg(arp, long) : (QWORD)va_arg(arp, unsigned long); + } else { /* int/short/char argument */ + v = (tc == 'd') ? (QWORD)(long long)va_arg(arp, int) : (QWORD)va_arg(arp, unsigned int); } if (tc == 'd' && (v & 0x8000000000000000)) { /* Negative value? */ v = 0 - v; f |= 1; @@ -6936,9 +7032,15 @@ int f_printf ( } while (v && i < SZ_NUM_BUF); if (f & 1) str[i++] = '-'; /* Sign */ /* Write it */ - for (j = i; !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ - do putc_bfd(&pb, (TCHAR)str[--i]); while (i); /* Body */ - while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ + for (j = i; !(f & 2) && j < w; j++) { /* Left pads */ + putc_bfd(&pb, pad); + } + do { /* Body */ + putc_bfd(&pb, (TCHAR)str[--i]); + } while (i); + while (j++ < w) { /* Right pads */ + putc_bfd(&pb, ' '); + } } va_end(arp); @@ -6961,12 +7063,12 @@ FRESULT f_setcp ( ) { static const WORD validcp[22] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; - static const BYTE* const tables[22] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct855, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; + static const BYTE *const tables[22] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct855, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; UINT i; for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ - if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ + if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ CodePage = cp; if (cp >= 900) { /* DBCS */ diff --git a/stm-firmware/fatfs/ffsystem.c b/stm-firmware/fatfs/ffsystem.c index 6fe5621..170f101 100644 --- a/stm-firmware/fatfs/ffsystem.c +++ b/stm-firmware/fatfs/ffsystem.c @@ -1,170 +1,208 @@ /*------------------------------------------------------------------------*/ -/* Sample Code of OS Dependent Functions for FatFs */ -/* (C)ChaN, 2018 */ +/* A Sample Code of User Provided OS Dependent Functions for FatFs */ /*------------------------------------------------------------------------*/ - #include -#if FF_USE_LFN == 3 /* Dynamic memory allocation */ +#if FF_USE_LFN == 3 /* Use dynamic memory allocation */ /*------------------------------------------------------------------------*/ -/* Allocate a memory block */ +/* Allocate/Free a Memory Block */ /*------------------------------------------------------------------------*/ +#include /* with POSIX API */ + + void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ UINT msize /* Number of bytes to allocate */ ) { - return malloc(msize); /* Allocate a new memory block with POSIX API */ + return malloc((size_t)msize); /* Allocate a new memory block */ } -/*------------------------------------------------------------------------*/ -/* Free a memory block */ -/*------------------------------------------------------------------------*/ - void ff_memfree ( - void* mblock /* Pointer to the memory block to free (nothing to do if null) */ + void* mblock /* Pointer to the memory block to free (no effect if null) */ ) { - free(mblock); /* Free the memory block with POSIX API */ + free(mblock); /* Free the memory block */ } #endif + #if FF_FS_REENTRANT /* Mutal exclusion */ - /*------------------------------------------------------------------------*/ -/* Create a Synchronization Object */ +/* Definitions of Mutex */ /*------------------------------------------------------------------------*/ -/* This function is called in f_mount() function to create a new -/ synchronization object for the volume, such as semaphore and mutex. -/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR. -*/ -//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */ +#define OS_TYPE 0 /* 0:Win32, 1:uITRON4.0, 2:uC/OS-II, 3:FreeRTOS, 4:CMSIS-RTOS */ -int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ - BYTE vol, /* Corresponding volume (logical drive number) */ - FF_SYNC_t* sobj /* Pointer to return the created sync object */ -) -{ - /* Win32 */ - *sobj = CreateMutex(NULL, FALSE, NULL); - return (int)(*sobj != INVALID_HANDLE_VALUE); +#if OS_TYPE == 0 /* Win32 */ +#include +static HANDLE Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */ - /* uITRON */ -// T_CSEM csem = {TA_TPRI,1,1}; -// *sobj = acre_sem(&csem); -// return (int)(*sobj > 0); +#elif OS_TYPE == 1 /* uITRON */ +#include "itron.h" +#include "kernel.h" +static mtxid Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */ - /* uC/OS-II */ -// OS_ERR err; -// *sobj = OSMutexCreate(0, &err); -// return (int)(err == OS_NO_ERR); +#elif OS_TYPE == 2 /* uc/OS-II */ +#include "includes.h" +static OS_EVENT *Mutex[FF_VOLUMES + 1]; /* Table of mutex pinter */ - /* FreeRTOS */ -// *sobj = xSemaphoreCreateMutex(); -// return (int)(*sobj != NULL); +#elif OS_TYPE == 3 /* FreeRTOS */ +#include "FreeRTOS.h" +#include "semphr.h" +static SemaphoreHandle_t Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */ - /* CMSIS-RTOS */ -// *sobj = osMutexCreate(&Mutex[vol]); -// return (int)(*sobj != NULL); -} - - -/*------------------------------------------------------------------------*/ -/* Delete a Synchronization Object */ -/*------------------------------------------------------------------------*/ -/* This function is called in f_mount() function to delete a synchronization -/ object that created with ff_cre_syncobj() function. When a 0 is returned, -/ the f_mount() function fails with FR_INT_ERR. -*/ - -int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ - FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ -) -{ - /* Win32 */ - return (int)CloseHandle(sobj); - - /* uITRON */ -// return (int)(del_sem(sobj) == E_OK); - - /* uC/OS-II */ -// OS_ERR err; -// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); -// return (int)(err == OS_NO_ERR); - - /* FreeRTOS */ -// vSemaphoreDelete(sobj); -// return 1; - - /* CMSIS-RTOS */ -// return (int)(osMutexDelete(sobj) == osOK); -} - - -/*------------------------------------------------------------------------*/ -/* Request Grant to Access the Volume */ -/*------------------------------------------------------------------------*/ -/* This function is called on entering file functions to lock the volume. -/ When a 0 is returned, the file function fails with FR_TIMEOUT. -*/ - -int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ - FF_SYNC_t sobj /* Sync object to wait */ -) -{ - /* Win32 */ - return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); - - /* uITRON */ -// return (int)(wai_sem(sobj) == E_OK); - - /* uC/OS-II */ -// OS_ERR err; -// OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); -// return (int)(err == OS_NO_ERR); - - /* FreeRTOS */ -// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); - - /* CMSIS-RTOS */ -// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); -} - - -/*------------------------------------------------------------------------*/ -/* Release Grant to Access the Volume */ -/*------------------------------------------------------------------------*/ -/* This function is called on leaving file functions to unlock the volume. -*/ - -void ff_rel_grant ( - FF_SYNC_t sobj /* Sync object to be signaled */ -) -{ - /* Win32 */ - ReleaseMutex(sobj); - - /* uITRON */ -// sig_sem(sobj); - - /* uC/OS-II */ -// OSMutexPost(sobj); - - /* FreeRTOS */ -// xSemaphoreGive(sobj); - - /* CMSIS-RTOS */ -// osMutexRelease(sobj); -} +#elif OS_TYPE == 4 /* CMSIS-RTOS */ +#include "cmsis_os.h" +static osMutexId Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */ #endif + + +/*------------------------------------------------------------------------*/ +/* Create a Mutex */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount function to create a new mutex +/ or semaphore for the volume. When a 0 is returned, the f_mount function +/ fails with FR_INT_ERR. +*/ + +int ff_mutex_create ( /* Returns 1:Function succeeded or 0:Could not create the mutex */ + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + Mutex[vol] = CreateMutex(NULL, FALSE, NULL); + return (int)(Mutex[vol] != INVALID_HANDLE_VALUE); + +#elif OS_TYPE == 1 /* uITRON */ + T_CMTX cmtx = {TA_TPRI,1}; + + Mutex[vol] = acre_mtx(&cmtx); + return (int)(Mutex[vol] > 0); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OS_ERR err; + + Mutex[vol] = OSMutexCreate(0, &err); + return (int)(err == OS_NO_ERR); + +#elif OS_TYPE == 3 /* FreeRTOS */ + Mutex[vol] = xSemaphoreCreateMutex(); + return (int)(Mutex[vol] != NULL); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + osMutexDef(cmsis_os_mutex); + + Mutex[vol] = osMutexCreate(osMutex(cmsis_os_mutex)); + return (int)(Mutex[vol] != NULL); + +#endif +} + + +/*------------------------------------------------------------------------*/ +/* Delete a Mutex */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount function to delete a mutex or +/ semaphore of the volume created with ff_mutex_create function. +*/ + +void ff_mutex_delete ( /* Returns 1:Function succeeded or 0:Could not delete due to an error */ + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + CloseHandle(Mutex[vol]); + +#elif OS_TYPE == 1 /* uITRON */ + del_mtx(Mutex[vol]); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OS_ERR err; + + OSMutexDel(Mutex[vol], OS_DEL_ALWAYS, &err); + +#elif OS_TYPE == 3 /* FreeRTOS */ + vSemaphoreDelete(Mutex[vol]); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + osMutexDelete(Mutex[vol]); + +#endif +} + + +/*------------------------------------------------------------------------*/ +/* Request a Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on enter file functions to lock the volume. +/ When a 0 is returned, the file function fails with FR_TIMEOUT. +*/ + +int ff_mutex_take ( /* Returns 1:Succeeded or 0:Timeout */ + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + return (int)(WaitForSingleObject(Mutex[vol], FF_FS_TIMEOUT) == WAIT_OBJECT_0); + +#elif OS_TYPE == 1 /* uITRON */ + return (int)(tloc_mtx(Mutex[vol], FF_FS_TIMEOUT) == E_OK); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OS_ERR err; + + OSMutexPend(Mutex[vol], FF_FS_TIMEOUT, &err)); + return (int)(err == OS_NO_ERR); + +#elif OS_TYPE == 3 /* FreeRTOS */ + return (int)(xSemaphoreTake(Mutex[vol], FF_FS_TIMEOUT) == pdTRUE); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + return (int)(osMutexWait(Mutex[vol], FF_FS_TIMEOUT) == osOK); + +#endif +} + + + +/*------------------------------------------------------------------------*/ +/* Release a Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on leave file functions to unlock the volume. +*/ + +void ff_mutex_give ( + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + ReleaseMutex(Mutex[vol]); + +#elif OS_TYPE == 1 /* uITRON */ + unl_mtx(Mutex[vol]); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OSMutexPost(Mutex[vol]); + +#elif OS_TYPE == 3 /* FreeRTOS */ + xSemaphoreGive(Mutex[vol]); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + osMutexRelease(Mutex[vol]); + +#endif +} + +#endif /* FF_FS_REENTRANT */ + diff --git a/stm-firmware/fatfs/ffunicode.c b/stm-firmware/fatfs/ffunicode.c index c1d61b5..1b24e60 100644 --- a/stm-firmware/fatfs/ffunicode.c +++ b/stm-firmware/fatfs/ffunicode.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------*/ -/* Unicode handling functions for FatFs R0.13+ */ +/* Unicode Handling Functions for FatFs R0.13 and Later */ +/*------------------------------------------------------------------------*/ +/* This module will occupy a huge memory in the .rodata section when the */ +/* FatFs is configured for LFN with DBCS. If the system has a Unicode */ +/* library for the code conversion, this module should be modified to use */ +/* it to avoid silly memory consumption. */ /*------------------------------------------------------------------------*/ -/* This module will occupy a huge memory in the .const section when the / -/ FatFs is configured for LFN with DBCS. If the system has any Unicode / -/ utilitiy for the code conversion, this module should be modified to use / -/ that function to avoid silly memory consumption. / -/-------------------------------------------------------------------------*/ /* -/ Copyright (C) 2014, ChaN, all right reserved. +/ Copyright (C) 2022, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -25,7 +25,7 @@ #include -#if FF_USE_LFN /* This module will be blanked if non-LFN configuration */ +#if FF_USE_LFN != 0 /* This module will be blanked if in non-LFN configuration */ #define MERGE2(a, b) a ## b #define CVTBL(tbl, cp) MERGE2(tbl, cp) @@ -15214,8 +15214,8 @@ static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */ /*------------------------------------------------------------------------*/ -/* OEM <==> Unicode conversions for static code page configuration */ -/* SBCS fixed code page */ +/* OEM <==> Unicode Conversions for Static Code Page Configuration with */ +/* SBCS Fixed Code Page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 @@ -15225,7 +15225,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ ) { WCHAR c = 0; - const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); + const WCHAR* p = CVTBL(uc, FF_CODE_PAGE); if (uni < 0x80) { /* ASCII? */ @@ -15247,7 +15247,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ ) { WCHAR c = 0; - const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); + const WCHAR* p = CVTBL(uc, FF_CODE_PAGE); if (oem < 0x80) { /* ASCII? */ @@ -15267,8 +15267,8 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ /*------------------------------------------------------------------------*/ -/* OEM <==> Unicode conversions for static code page configuration */ -/* DBCS fixed code page */ +/* OEM <==> Unicode Conversions for Static Code Page Configuration with */ +/* DBCS Fixed Code Page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE >= 900 @@ -15277,7 +15277,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0, uc; UINT i = 0, n, li, hi; @@ -15313,7 +15313,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0; UINT i = 0, n, li, hi; @@ -15346,7 +15346,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ /*------------------------------------------------------------------------*/ -/* OEM <==> Unicode conversions for dynamic code page configuration */ +/* OEM <==> Unicode Conversions for Dynamic Code Page Configuration */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE == 0 @@ -15360,7 +15360,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0, uc; UINT i, n, li, hi; @@ -15412,7 +15412,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0; UINT i, n, li, hi; @@ -15458,14 +15458,14 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ /*------------------------------------------------------------------------*/ -/* Unicode up-case conversion */ +/* Unicode Up-case Conversion */ /*------------------------------------------------------------------------*/ DWORD ff_wtoupper ( /* Returns up-converted code point */ DWORD uni /* Unicode code point to be up-converted */ ) { - const WORD *p; + const WORD* p; WORD uc, bc, nc, cmd; static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ /* Basic Latin */ @@ -15590,4 +15590,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */ } -#endif /* #if FF_USE_LFN */ +#endif /* #if FF_USE_LFN != 0 */ diff --git a/stm-firmware/hw-version-detect.c b/stm-firmware/hw-version-detect.c index 64df7f4..7dee01e 100644 --- a/stm-firmware/hw-version-detect.c +++ b/stm-firmware/hw-version-detect.c @@ -27,10 +27,15 @@ #include #include +#if HW_REV_DETECT_PIN_LOW > HW_REV_DETECT_PIN_HIGH +#error Configuration error for Hardware derection pins. Lowest position must be less than the highest pin position. +#endif + enum hw_revision get_pcb_hardware_version(void) { uint8_t current_pin; - uint16_t port_bitmask = 0U; + uint16_t port_bitmask = 0U; /* Use uint16_t because a port can have 16 IOs max. */ + const uint16_t highest_bit_mask = (1 << (HW_REV_DETECT_PIN_HIGH - HW_REV_DETECT_PIN_LOW)); static enum hw_revision revision = HW_REV_NOT_DETECTED; /* If the revision has been previously detected, @@ -53,7 +58,7 @@ enum hw_revision get_pcb_hardware_version(void) */ for (current_pin = HW_REV_DETECT_PIN_LOW; current_pin <= HW_REV_DETECT_PIN_HIGH; current_pin++) { port_bitmask >>= 1; - port_bitmask |= (HW_REV_DETECT_GPIO->IDR & (1 << current_pin)) ? 0x0 : 0x80; + port_bitmask |= (HW_REV_DETECT_GPIO->IDR & (1 << current_pin)) ? 0x0 : highest_bit_mask; } /* Resolve the read in bitmask to a hardware version */ diff --git a/stm-firmware/include/fatfs/ff.h b/stm-firmware/include/fatfs/ff.h index 64bf79d..d88febc 100644 --- a/stm-firmware/include/fatfs/ff.h +++ b/stm-firmware/include/fatfs/ff.h @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem module R0.14b / +/ FatFs - Generic FAT Filesystem module R0.15 / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2021, ChaN, all right reserved. +/ Copyright (C) 2022, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -20,7 +20,7 @@ #ifndef FF_DEFINED -#define FF_DEFINED 86631 /* Revision ID */ +#define FF_DEFINED 80286 /* Revision ID */ #ifdef __cplusplus extern "C" { @@ -131,10 +131,11 @@ extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ typedef struct { BYTE fs_type; /* Filesystem type (0:not mounted) */ - BYTE pdrv; /* Associated physical drive */ + BYTE pdrv; /* Volume hosting physical drive */ + BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */ BYTE n_fats; /* Number of FATs (1 or 2) */ - BYTE wflag; /* win[] flag (b0:dirty) */ - BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ + BYTE wflag; /* win[] status (b0:dirty) */ + BYTE fsi_flag; /* FSINFO status (b7:disabled, b0:dirty) */ WORD id; /* Volume mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD csize; /* Cluster size [sectors] */ @@ -147,9 +148,6 @@ typedef struct { #if FF_FS_EXFAT BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ #endif -#if FF_FS_REENTRANT - FF_SYNC_t sobj; /* Identifier of sync object */ -#endif #if !FF_FS_READONLY DWORD last_clst; /* Last allocated cluster */ DWORD free_clst; /* Number of free clusters */ @@ -163,10 +161,10 @@ typedef struct { #endif #endif DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ - DWORD fsize; /* Size of an FAT [sectors] */ + DWORD fsize; /* Number of sectors per FAT */ LBA_t volbase; /* Volume base sector */ LBA_t fatbase; /* FAT base sector */ - LBA_t dirbase; /* Root directory base sector/cluster */ + LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */ LBA_t database; /* Data base sector */ #if FF_FS_EXFAT LBA_t bitbase; /* Allocation bitmap base sector */ @@ -181,7 +179,7 @@ typedef struct { typedef struct { FATFS* fs; /* Pointer to the hosting volume of this object */ - WORD id; /* Hosting volume mount ID */ + WORD id; /* Hosting volume's mount ID */ BYTE attr; /* Object attribute */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ @@ -250,7 +248,7 @@ typedef struct { WORD ftime; /* Modified time */ BYTE fattrib; /* File attribute */ #if FF_USE_LFN - TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ + TCHAR altname[FF_SFN_BUF + 1];/* Alternative file name */ TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ #else TCHAR fname[12 + 1]; /* File name */ @@ -298,8 +296,10 @@ typedef enum { + +/*--------------------------------------------------------------*/ +/* FatFs Module Application Interface */ /*--------------------------------------------------------------*/ -/* FatFs module application interface */ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_close (FIL* fp); /* Close an open file object */ @@ -336,6 +336,8 @@ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ +/* Some API fucntions are implemented as macro */ + #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) #define f_tell(fp) ((fp)->fptr) @@ -349,38 +351,43 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil /*--------------------------------------------------------------*/ -/* Additional user defined functions */ +/* Additional Functions */ +/*--------------------------------------------------------------*/ -/* RTC function */ +/* RTC function (provided by user) */ #if !FF_FS_READONLY && !FF_FS_NORTC -DWORD get_fattime (void); +DWORD get_fattime (void); /* Get current time */ #endif -/* LFN support functions */ -#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ + +/* LFN support functions (defined in ffunicode.c) */ + +#if FF_USE_LFN >= 1 WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ #endif -#if FF_USE_LFN == 3 /* Dynamic memory allocation */ -void* ff_memalloc (UINT msize); /* Allocate memory block */ -void ff_memfree (void* mblock); /* Free memory block */ -#endif -/* Sync functions */ -#if FF_FS_REENTRANT -int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ -int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ -void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ -int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ + +/* O/S dependent functions (samples available in ffsystem.c) */ + +#if FF_USE_LFN == 3 /* Dynamic memory allocation */ +void* ff_memalloc (UINT msize); /* Allocate memory block */ +void ff_memfree (void* mblock); /* Free memory block */ +#endif +#if FF_FS_REENTRANT /* Sync functions */ +int ff_mutex_create (int vol); /* Create a sync object */ +void ff_mutex_delete (int vol); /* Delete a sync object */ +int ff_mutex_take (int vol); /* Lock sync object */ +void ff_mutex_give (int vol); /* Unlock sync object */ #endif /*--------------------------------------------------------------*/ -/* Flags and offset address */ - +/* Flags and Offset Address */ +/*--------------------------------------------------------------*/ /* File access mode and open method flags (3rd argument of f_open) */ #define FA_READ 0x01 diff --git a/stm-firmware/include/fatfs/ffconf.h b/stm-firmware/include/fatfs/ffconf.h index 77da460..601d68f 100644 --- a/stm-firmware/include/fatfs/ffconf.h +++ b/stm-firmware/include/fatfs/ffconf.h @@ -1,8 +1,8 @@ /*---------------------------------------------------------------------------/ -/ FatFs Functional Configurations +/ Configurations of FatFs Module /---------------------------------------------------------------------------*/ -#define FFCONF_DEF 86631 /* Revision ID */ +#define FFCONF_DEF 80286 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -68,7 +68,7 @@ / 2: Enable with LF-CRLF conversion. / / FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 - makes f_printf() support floating point argument. These features want C99 or later. +/ makes f_printf() support floating point argument. These features want C99 or later. / When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character / encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE / to be read/written via those functions. @@ -178,7 +178,7 @@ / logical drives. Number of items must not be less than FF_VOLUMES. Valid / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is -/ not defined, a user defined volume string table needs to be defined as: +/ not defined, a user defined volume string table is needed as: / / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... */ @@ -190,7 +190,7 @@ / number and only an FAT volume found on the physical drive will be mounted. / When this function is enabled (1), each logical drive number can be bound to / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() -/ funciton will be available. */ +/ function will be available. */ #define FF_MIN_SS 512 @@ -240,10 +240,10 @@ #define FF_FS_NORTC 0 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 -#define FF_NORTC_YEAR 2020 -/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have -/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable -/ the timestamp function. Every object modified by FatFs will have a fixed timestamp +#define FF_NORTC_YEAR 2022 +/* The option FF_FS_NORTC switches timestamp feature. If the system does not have +/ an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the +/ timestamp feature. Every object modified by FatFs will have a fixed timestamp / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / added to the project to read current time form real-time clock. FF_NORTC_MON, @@ -253,7 +253,7 @@ #define FF_FS_NOFSINFO 0 /* If you need to know correct free space on the FAT32 volume, set bit 0 of this -/ option, and f_getfree() function at first time after volume mount will force +/ option, and f_getfree() function at the first time after volume mount will force / a full FAT scan. Bit 1 controls the use of last allocated cluster number. / / bit0=0: Use free cluster count in the FSINFO if available. @@ -275,26 +275,21 @@ / lock control is independent of re-entrancy. */ -/* #include // O/S definitions */ #define FF_FS_REENTRANT 0 #define FF_FS_TIMEOUT 1000 -#define FF_SYNC_t HANDLE /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / and f_fdisk() function, are always not re-entrant. Only file/directory access -/ to the same volume is under control of this function. +/ to the same volume is under control of this featuer. / -/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. +/ 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, -/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() -/ function, must be added to the project. Samples are available in -/ option/syscall.c. +/ ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give() +/ function, must be added to the project. Samples are available in ffsystem.c. / -/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. -/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, -/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be -/ included somewhere in the scope of ff.h. */ +/ The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick. +*/ diff --git a/stm-firmware/include/reflow-controller/hw-version-detect.h b/stm-firmware/include/reflow-controller/hw-version-detect.h index ef9721a..ff41ea4 100644 --- a/stm-firmware/include/reflow-controller/hw-version-detect.h +++ b/stm-firmware/include/reflow-controller/hw-version-detect.h @@ -48,7 +48,6 @@ */ #define HW_REV_DETECT_PIN_HIGH (15U) - /** * @brief PCB/Hardware Revision Type */ diff --git a/stm-firmware/include/reflow-controller/main-cycle-counter.h b/stm-firmware/include/reflow-controller/main-cycle-counter.h index 90564ad..a9123c1 100644 --- a/stm-firmware/include/reflow-controller/main-cycle-counter.h +++ b/stm-firmware/include/reflow-controller/main-cycle-counter.h @@ -30,10 +30,16 @@ #include /** - * @brief Initialize/Reset the main cycle counter to 0. + * @brief Initialize the main cycle counter and reset to 0. This also enables the core cycle counter * This function can be called multiple times. */ -void main_cycle_counter_init(void); +void main_and_core_cycle_counter_init(void); + +/** + * @brief Reset the main cycle counter. + * @note This does not reset the core cycle counter + */ +void main_cycle_counter_reset(void); /** * @brief Increment the main cycle counter by 1 @@ -46,6 +52,18 @@ void main_cycle_counter_inc(void); */ uint64_t main_cycle_counter_get(void); +/** + * @brief Reset the core cycle counter to 0 + */ +void core_cycle_counter_reset(void); + +/** + * @brief Get the current value of the core cycle counter + * + * @return uint32_t Counter value + */ +uint32_t core_cycle_counter_get(void); + #endif /* __MAIN_CYCLE_COUNTER_H__ */ /** @} */ diff --git a/stm-firmware/include/reflow-controller/safety/flash-crc-struct.h b/stm-firmware/include/reflow-controller/safety/flash-crc-struct.h new file mode 100644 index 0000000..7166eaf --- /dev/null +++ b/stm-firmware/include/reflow-controller/safety/flash-crc-struct.h @@ -0,0 +1,37 @@ +/* Reflow Oven Controller +* +* Copyright (C) 2022 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 . +*/ + +#ifndef _SAFETY_FLASH_CRC_STRUCT_H_ +#define _SAFETY_FLASH_CRC_STRUCT_H_ + +#include + +struct flash_crcs { + uint32_t start_magic; + uint32_t crc_section_text; + uint32_t crc_section_data; + uint32_t crc_section_ccm_data; + uint32_t crc_section_vectors; + uint32_t end_magic; +}; + +extern const struct flash_crcs crcs_in_flash; + +#endif /* _SAFETY_FLASH_CRC_STRUCT_H_ */ diff --git a/stm-firmware/include/reflow-controller/safety/flash-crc.h b/stm-firmware/include/reflow-controller/safety/flash-crc.h new file mode 100644 index 0000000..174dc81 --- /dev/null +++ b/stm-firmware/include/reflow-controller/safety/flash-crc.h @@ -0,0 +1,56 @@ +/* Reflow Oven Controller +* +* Copyright (C) 2022 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 . +*/ + +#ifndef _SAFETY_FLASH_CRC_H_ +#define _SAFETY_FLASH_CRC_H_ + +#include + +enum flash_crc_section { + FLASH_CRC_VECTOR = 0, + FLASH_CRC_TEXT, + FLASH_CRC_DATA, + FLASH_CRC_CCMDATA, + N_FLASH_CRC, +}; + +/** + * @brief Perform a CRC check of the flash memory and set appropriate flags + * @return negative if internal error occured. Otherwise (independent from CRC check result) 0. + * @note This function requires the safety controller (and CRC unit) to be set up before calling! + */ +int flash_crc_trigger_check(void); + +/** + * @brief Calculate CRC over flash section + * @param sec Section to calculate CRC over + * @param[out] crc_result Calculated CRC + * @return negative if internal error occured. Otherwise (independent from CRC check result) 0. + */ +int flash_crc_calc_section(enum flash_crc_section sec, uint32_t *crc_result); + +/** + * @brief Get expected CRC value of a section + * @param sec Section + * @return Expected CRC + */ +uint32_t flash_crc_get_expected_crc(enum flash_crc_section sec); + +#endif /* _SAFETY_FLASH_CRC_H_ */ diff --git a/stm-firmware/include/reflow-controller/safety/safety-config.h b/stm-firmware/include/reflow-controller/safety/safety-config.h index 009ef27..b1b0d4c 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-config.h +++ b/stm-firmware/include/reflow-controller/safety/safety-config.h @@ -27,6 +27,15 @@ #ifndef __SAFETY_CONFIG_H__ #define __SAFETY_CONFIG_H__ +/** + * @brief Weights of error flags. + */ +enum config_weight { + SAFETY_FLAG_CONFIG_WEIGHT_NONE = 0, /**< @brief This flag has no global error consequence, but might be respected by certain software modules. */ + SAFETY_FLAG_CONFIG_WEIGHT_PID = 1, /**< @brief This flag will force a stop of the temperature PID controller */ + SAFETY_FLAG_CONFIG_WEIGHT_PANIC = 2, /**< @brief This flag will trigger the panic mode */ +}; + /** * @brief Enum type representing safety flags. * @@ -60,6 +69,7 @@ enum safety_flag { ERR_FLAG_FLASH_CRC_DATA = (1<<20), ERR_FLAG_CFG_CRC_MEAS_ADC = (1<<21), ERR_FLAG_CFG_CRC_SAFETY_ADC = (1<<22), + ERR_FLAG_CFG_CRC_MISC = (1<<23), }; /** @@ -78,6 +88,7 @@ enum timing_monitor { enum crc_monitor { ERR_CRC_MON_MEAS_ADC = 0, ERR_CRC_MON_SAFETY_ADC, + ERR_CRC_MON_MISC, N_ERR_CRC_MON }; @@ -115,7 +126,15 @@ enum analog_value_monitor { #define WATCHDOG_HALT_DEBUG (0) #endif -#define WATCHDOG_PRESCALER 16 +/** + * @brief Watchdog clock prescaler value + */ +#define WATCHDOG_PRESCALER (16) + +/** + * @brief Watchdog reload value + */ +#define WATCHDOG_RELOAD_VALUE (2500) /** * @brief Minimum number of bytes that have to be free on the stack. If this is not the case, an error is detected @@ -159,7 +178,13 @@ enum analog_value_monitor { #define SAFETY_CRC_MON_SAFETY_ADC_PW 0xA8DF2368 /** - * @brief Default persistence of safety flags. These values are loaded into the safety tables on startup + * @brief Password for resetting ERR_CRC_MON_MISC + * + */ +#define SAFETY_CRC_MON_MISC_PW 0x9A62E96A + +/** + * @brief Default persistence of safety flags. These values are loaded into the safety tables on startup. */ #define SAFETY_CONFIG_DEFAULT_PERSIST ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, false), \ @@ -184,8 +209,9 @@ enum analog_value_monitor { ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_FLASH_CRC_DATA, true), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, true), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, true), \ + ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_MISC, true), /** - * @brief Default config weights of safety flags. These values are loaded into the safety tables on startup + * @brief Default config weights of safety flags. These values are loaded into the safety tables on startup. */ #define SAFETY_CONFIG_DEFAULT_WEIGHTS ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OFF, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ @@ -206,9 +232,10 @@ enum analog_value_monitor { ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_OVERTEMP, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ - ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_CODE, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ - ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_DATA, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ - ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ - ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_CODE, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_DATA, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_MISC, SAFETY_FLAG_CONFIG_WEIGHT_PANIC) #endif /* __SAFETY_CONFIG_H__ */ diff --git a/stm-firmware/include/reflow-controller/safety/safety-controller.h b/stm-firmware/include/reflow-controller/safety/safety-controller.h index a882d69..98ed431 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-controller.h +++ b/stm-firmware/include/reflow-controller/safety/safety-controller.h @@ -70,14 +70,14 @@ struct timing_monitor_info { * You have to call safety_controller_handle * If this function fails, it will hang, because errors in the safety controller are not recoverable */ -void safety_controller_init(); +void safety_controller_init(void); /** * @brief Handle the safety controller. * @note This function must be executed periodically in order to prevent the watchdog from resetting the firmware - * @return 0 if successful + * @returns Worst flag weigth that is currently set. */ -int safety_controller_handle(); +enum config_weight safety_controller_handle(void); /** * @brief Report one or multiple errors to the safety controller @@ -170,13 +170,13 @@ bool safety_controller_get_flags_by_mask(enum safety_flag mask); * @brief Get the count of error flags * @return Error flag count */ -uint32_t safety_controller_get_flag_count(); +uint32_t safety_controller_get_flag_count(void); /** * @brief Get the count of analog monitors * @return Analog monitor count */ -uint32_t safety_controller_get_analog_monitor_count(); +uint32_t safety_controller_get_analog_monitor_count(void); /** * @brief Get an error flag's name by its index. @@ -267,13 +267,6 @@ int safety_controller_set_overtemp_limit(float over_temperature); */ float safety_controller_get_overtemp_limit(void); -/** - * @brief Perform a CRC check of the flash memory and set appropriate flags - * @return negative if internal error occured. Otherwise (independent from CRC check result) 0. - * @note This function requires the safety controller to be set up before! - */ -int safety_controller_trigger_flash_crc_check(void); - /** * @brief Recalculate the CRC of a given CRC Monitor. This has to be done once the supervised registers update * @param mon Monitor to recalculate diff --git a/stm-firmware/include/reflow-controller/safety/safety-memory.h b/stm-firmware/include/reflow-controller/safety/safety-memory.h index 0d03b0f..18e6094 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-memory.h +++ b/stm-firmware/include/reflow-controller/safety/safety-memory.h @@ -24,6 +24,7 @@ #include #include #include +#include /** @addtogroup safety-memory * @{ @@ -131,15 +132,6 @@ enum config_override_entry_type { SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE = 2, }; -/** - * @brief Weights of error flags. - */ -enum config_weight { - SAFETY_FLAG_CONFIG_WEIGHT_NONE = 0, /**< @brief This flag has no global error consequence, but might be respected by certain software modules. */ - SAFETY_FLAG_CONFIG_WEIGHT_PID = 1, /**< @brief This flag will force a stop of the temperature PID controller */ - SAFETY_FLAG_CONFIG_WEIGHT_PANIC = 2, /**< @brief This flag will trigger the panic mode */ -}; - /** * @brief representation of a config override memory entry */ diff --git a/stm-firmware/include/reflow-controller/safety/watchdog.h b/stm-firmware/include/reflow-controller/safety/watchdog.h index 6d283cd..b9cfc17 100644 --- a/stm-firmware/include/reflow-controller/safety/watchdog.h +++ b/stm-firmware/include/reflow-controller/safety/watchdog.h @@ -27,11 +27,19 @@ /** * @brief Setup the watchdog for the safety controller - * @param Prescaler to use for the 32 KHz LSI clock + * + * The watchdog timeout can be calculated with: + * \f[ t = \frac{(\mathrm{RELOAD_VAL} + 1)\cdot \mathrm{PRESCALER}}{32000 } s\f] + * + * Valid prescaler values are: 4, 8, 16, 32, 64, 128, 256. + * @param prescaler Prescaler to use for the 32 KHz LSI clock + * @param reload_value Reload value to reload the timer with when reset. 0 to 0xFFF * @return 0 if successful + * @return -1 if prescaler is wrong + * @return -2 if a reload value > 0xFFF is selected. 0xFFF will be used in this case * @note Once the watchdog is enabled, it cannot be turned off! */ -int watchdog_setup(uint8_t prescaler); +int watchdog_setup(uint16_t prescaler, uint16_t reload_value); /** * @brief Reset watchdog counter diff --git a/stm-firmware/include/reflow-controller/sd.h b/stm-firmware/include/reflow-controller/sd.h new file mode 100644 index 0000000..5233a71 --- /dev/null +++ b/stm-firmware/include/reflow-controller/sd.h @@ -0,0 +1,42 @@ +/* Reflow Oven Controller + * + * Copyright (C) 2022 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. + * + * GDSII-Converter 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 . + */ + + #ifndef _SD_H_ + #define _SD_H_ + +#include +#include + +/** + * @brief Mount the SD card if available and not already mounted + * @param fs Filesystem to mount to. + * @return true if mounted, false if an error occured or the SD is not inserted and cannot be mounted + */ +bool mount_sd_card_if_avail(FATFS *fs); + +/** + * @brief Return whether an SD card is inserted and mounted + * + * @return true SD inserted and mounted + * @return false No SD inserted or not mounted + */ +bool sd_card_is_mounted(void); + +#endif /* _SD_H_ */ \ No newline at end of file diff --git a/stm-firmware/include/reflow-controller/settings/spi-eeprom.h b/stm-firmware/include/reflow-controller/settings/spi-eeprom.h index c6a1f14..f601491 100644 --- a/stm-firmware/include/reflow-controller/settings/spi-eeprom.h +++ b/stm-firmware/include/reflow-controller/settings/spi-eeprom.h @@ -28,12 +28,12 @@ * @brief Initialize the SPI for the eeprom. * @return 0 if succesful */ -int spi_eeprom_init(); +int spi_eeprom_init(void); /** * @brief Uninitialize the SPI EEPROM */ -void spi_eeprom_deinit(); +void spi_eeprom_deinit(void); /** * @brief Read from SPI EEPROM diff --git a/stm-firmware/include/reflow-controller/version.h b/stm-firmware/include/reflow-controller/version.h new file mode 100644 index 0000000..96e5e6a --- /dev/null +++ b/stm-firmware/include/reflow-controller/version.h @@ -0,0 +1,29 @@ +/* Reflow Oven Controller + * + * Copyright (C) 2022 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 . + */ + +#ifndef _VERSION_H_ +#define _VERSION_H_ + +extern const char *version_git_version_string; +extern const char *version_git_full_commit_string; +extern const char *version_compile_date; +extern const char *version_compile_time; + +#endif /* _VERSION_H_ */ \ No newline at end of file diff --git a/stm-firmware/include/stm-periph/rng.h b/stm-firmware/include/stm-periph/rng.h index e8d9d7a..a010357 100644 --- a/stm-firmware/include/stm-periph/rng.h +++ b/stm-firmware/include/stm-periph/rng.h @@ -33,7 +33,7 @@ enum random_number_error { void random_number_gen_init(bool int_enable); -void random_number_gen_deinit(); +void random_number_gen_deinit(void); void random_number_gen_reset(bool int_en); diff --git a/stm-firmware/include/stm-periph/unique-id.h b/stm-firmware/include/stm-periph/unique-id.h index 7a8ef98..a00aa01 100644 --- a/stm-firmware/include/stm-periph/unique-id.h +++ b/stm-firmware/include/stm-periph/unique-id.h @@ -33,4 +33,6 @@ void stm_unique_id_get(uint32_t *high, uint32_t *mid, uint32_t *low); void stm_dev_rev_id_get(uint32_t *device_id, uint32_t *revision_id); +void stm_cpuid_get(uint8_t *implementer, uint8_t *variant, uint16_t *part_no, uint8_t *rev); + #endif /* __UNIQUE_ID_H__ */ diff --git a/stm-firmware/main-cycle-counter.c b/stm-firmware/main-cycle-counter.c index bb0d4e8..da55809 100644 --- a/stm-firmware/main-cycle-counter.c +++ b/stm-firmware/main-cycle-counter.c @@ -25,6 +25,7 @@ #include #include +#include /** * @brief Variable storing the main cycle counter. @@ -33,7 +34,22 @@ */ static uint64_t IN_SECTION(.ccm.bss) main_cycle_counter; -void main_cycle_counter_init(void) +void main_and_core_cycle_counter_init(void) +{ + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + + /* Enable the core cycle counter if available on current processor */ + if (!(DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk)) { + /* Cycle counter is available. Enable */ + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + } + + /* Reset the counters to 0 */ + main_cycle_counter_reset(); + core_cycle_counter_reset(); +} + +void main_cycle_counter_reset(void) { main_cycle_counter = 0ULL; } @@ -48,4 +64,14 @@ uint64_t main_cycle_counter_get(void) return main_cycle_counter; } +void core_cycle_counter_reset(void) +{ + DWT->CYCCNT = 0UL; +} + +uint32_t core_cycle_counter_get(void) +{ + return DWT->CYCCNT; +} + /** @} */ diff --git a/stm-firmware/main.c b/stm-firmware/main.c index dcf8145..b98f8e7 100644 --- a/stm-firmware/main.c +++ b/stm-firmware/main.c @@ -23,6 +23,7 @@ * @brief Main file for firmware */ +#include "reflow-controller/safety/safety-config.h" #include #include #include @@ -32,13 +33,13 @@ #include #include #include -#include "fatfs/shimatta_sdio_driver/shimatta_sdio.h" #include #include #include #include #include #include +#include #include #include #include @@ -88,40 +89,6 @@ static inline void uart_gpio_config(void) #endif } -/** - * @brief Mount the SD card if available and not already mounted - * @param mounted The current mounting state of the SD card - * @return true if mounted, false if an error occured or the SD is not inserted and cannot be mounted - */ -static bool mount_sd_card_if_avail(bool mounted) -{ - FRESULT res; - static uint8_t IN_SECTION(.ccm.bss) inserted_counter = 0; - - if (sdio_check_inserted() && mounted) { - memset(fs_ptr, 0, sizeof(FATFS)); - sdio_stop_clk(); - inserted_counter = 0; - return false; - } - - if (!sdio_check_inserted() && inserted_counter < 255) - inserted_counter++; - - if (!sdio_check_inserted() && !mounted && inserted_counter > 4) { - inserted_counter = 0; - res = f_mount(fs_ptr, "0:/", 1); - if (res == FR_OK) { - led_set(1, 1); - return true; - } else { - return false; - } - } - - return mounted; -} - /** * @brief Process the boot status structure in the safety (backup) RAM * Depending on the flags set there, this function will: @@ -249,6 +216,9 @@ static inline void setup_system(void) /** - Enable the ADC for PT1000 measurement */ adc_pt1000_setup_meas(); + + /** - Enable the misc CRC config monitor to supervise clock, systick and flash settings */ + (void)safety_controller_set_crc_monitor(ERR_CRC_MON_MISC, SAFETY_CRC_MON_MISC_PW); } /** @@ -286,6 +256,7 @@ int main(void) shellmatta_handle_t shell_handle; int menu_wait_request; uint64_t quarter_sec_timestamp = 0ULL; + enum config_weight worst_safety_flag = SAFETY_FLAG_CONFIG_WEIGHT_NONE; /** - Setup all the peripherals and external componets like LCD, EEPROM etc. and the safety controller */ setup_system(); @@ -301,8 +272,8 @@ int main(void) /** - Print motd to shell */ shell_print_motd(shell_handle); - /** - Set the main cycle counter to 0 */ - main_cycle_counter_init(); + /** - Set the main cycle counter to 0 and activate the core cycle counter if available */ + main_and_core_cycle_counter_init(); /** - Do a loop over the following */ while (1) { @@ -312,9 +283,9 @@ int main(void) * it is tried to load it from SD card. */ if (systick_ticks_have_passed(quarter_sec_timestamp, 250)) { - led_set(1, 0); + led_set(1u, 0); sd_old = sd_card_mounted; - sd_card_mounted = mount_sd_card_if_avail(sd_card_mounted); + sd_card_mounted = mount_sd_card_if_avail(fs_ptr); if (sd_card_mounted && !sd_old) { adc_pt1000_get_resistance_calibration(NULL, NULL, &cal_active); @@ -325,6 +296,14 @@ int main(void) } } + /* Check if any flags are present, that disable the PID controller. Blink + * LED 0 in this case + */ + if (worst_safety_flag >= SAFETY_FLAG_CONFIG_WEIGHT_PID) + led_set(0u, led_get(0u) ? 0 : 1); + else + led_set(0u, 0); + quarter_sec_timestamp = systick_get_global_tick(); } @@ -338,7 +317,7 @@ int main(void) temp_profile_executer_handle(); /** - Handle the safety controller. This must be called! Otherwise a watchdog reset will occur */ - safety_controller_handle(); + worst_safety_flag = safety_controller_handle(); /** - If the Oven PID controller is running, we handle its sample function */ if (oven_pid_get_status() == OVEN_PID_RUNNING) diff --git a/stm-firmware/safety/fault.c b/stm-firmware/safety/fault.c index 17237f3..3b80f72 100644 --- a/stm-firmware/safety/fault.c +++ b/stm-firmware/safety/fault.c @@ -78,5 +78,6 @@ void panic_mode(void) } /* Let the watchdog do the rest */ - while (1); + while (1) + ; } diff --git a/stm-firmware/safety/flash-crc-struct.c b/stm-firmware/safety/flash-crc-struct.c new file mode 100644 index 0000000..ebe7989 --- /dev/null +++ b/stm-firmware/safety/flash-crc-struct.c @@ -0,0 +1,31 @@ +/* Reflow Oven Controller +* +* Copyright (C) 2022 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 + +const struct flash_crcs IN_SECTION(.flashcrc) crcs_in_flash = { + .start_magic = 0xA8BE53F9UL, + .crc_section_ccm_data = 0UL, + .crc_section_text = 0UL, + .crc_section_data = 0UL, + .crc_section_vectors = 0UL, + .end_magic = 0xFFA582FFUL, +}; diff --git a/stm-firmware/safety/flash-crc.c b/stm-firmware/safety/flash-crc.c new file mode 100644 index 0000000..0840802 --- /dev/null +++ b/stm-firmware/safety/flash-crc.c @@ -0,0 +1,152 @@ +/* Reflow Oven Controller +* +* Copyright (C) 2022 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 + +extern const uint32_t __ld_vectors_start; +extern const uint32_t __ld_vectors_end; +extern const uint32_t __ld_text_start; +extern const uint32_t __ld_text_end; + +extern const uint32_t __ld_sdata_ccm; +extern const uint32_t __ld_edata_ccm; +extern const uint32_t __ld_load_ccm_data; + +extern const uint32_t __ld_sdata; +extern const uint32_t __ld_edata; +extern const uint32_t __ld_load_data; + + +int flash_crc_trigger_check(void) +{ + int ret = -1; + int res; + int any_err = 0; + uint32_t crc; + + /* Perform CRC check over vector table */ + res = flash_crc_calc_section(FLASH_CRC_VECTOR, &crc); + if (res || crc != flash_crc_get_expected_crc(FLASH_CRC_VECTOR)) + safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE); + any_err |= res; + + /* Perform CRC check over text section */ + res = flash_crc_calc_section(FLASH_CRC_TEXT, &crc); + if (res || crc != flash_crc_get_expected_crc(FLASH_CRC_TEXT)) + safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE); + any_err |= res; + + /* Perform CRC check over data section */ + res = flash_crc_calc_section(FLASH_CRC_DATA, &crc); + if (res || crc != flash_crc_get_expected_crc(FLASH_CRC_DATA)) + safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA); + any_err |= res; + + /* Perform CRC check over ccm data section */ + res = flash_crc_calc_section(FLASH_CRC_CCMDATA, &crc); + if (res || crc != flash_crc_get_expected_crc(FLASH_CRC_CCMDATA)) + safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA); + any_err |= res; + + if (!any_err) + ret = 0; + + return ret; +} + +int flash_crc_calc_section(enum flash_crc_section sec, uint32_t *crc_result) +{ + uint32_t len; + const uint32_t *startptr; + const uint32_t *endptr; + const uint32_t *load_addr = NULL; + + if (!crc_result) + return -1002; + + switch (sec) { + case FLASH_CRC_VECTOR: + startptr = &__ld_vectors_start; + endptr = &__ld_vectors_end; + break; + case FLASH_CRC_TEXT: + startptr = &__ld_text_start; + endptr = &__ld_text_end; + break; + case FLASH_CRC_DATA: + startptr = &__ld_sdata; + endptr = &__ld_edata; + load_addr = &__ld_load_data; + break; + case FLASH_CRC_CCMDATA: + startptr = &__ld_sdata_ccm; + endptr = &__ld_edata_ccm; + load_addr = &__ld_load_ccm_data; + break; + default: + return -1001; + } + + len = (uint32_t)((void *)endptr - (void *)startptr); + if (!load_addr) + load_addr = startptr; + + /* Not a multiple of 32bit words long. Cannot calculate CRC in this case! */ + if (len % 4) + return -1; + + /* Calculate word count */ + len /= 4; + + /* Reset CRC and calculate over data range */ + crc_unit_reset(); + crc_unit_input_array(load_addr, len); + *crc_result = crc_unit_get_crc(); + + return 0; +} + +uint32_t flash_crc_get_expected_crc(enum flash_crc_section sec) +{ + uint32_t crc; + + switch (sec) { + case FLASH_CRC_VECTOR: + crc = crcs_in_flash.crc_section_vectors; + break; + case FLASH_CRC_TEXT: + crc = crcs_in_flash.crc_section_text; + break; + case FLASH_CRC_DATA: + crc = crcs_in_flash.crc_section_data; + break; + case FLASH_CRC_CCMDATA: + crc = crcs_in_flash.crc_section_ccm_data; + break; + default: + crc = 0xFFFFFFFFul; + break; + } + + return crc; +} diff --git a/stm-firmware/safety/safety-adc.c b/stm-firmware/safety/safety-adc.c index 9ade7df..7f54a46 100644 --- a/stm-firmware/safety/safety-adc.c +++ b/stm-firmware/safety/safety-adc.c @@ -1,22 +1,22 @@ /* Reflow Oven Controller -* -* Copyright (C) 2020 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 . -*/ + * + * Copyright (C) 2020 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 . + */ /** * @addtogroup safety-adc @@ -60,7 +60,8 @@ void safety_adc_init(void) rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN)); if (hw_rev != HW_REV_V1_2) { - rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT_RCC_MASK)); + rcc_manager_enable_clock(&RCC->AHB1ENR, + BITMASK_TO_BITNO(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT_RCC_MASK)); SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER &= MODER_DELETE(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN); SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER |= ANALOG(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN); } @@ -72,7 +73,7 @@ void safety_adc_init(void) SAFETY_ADC_ADC_PERIPHERAL->SMPR1 |= ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16 | ADC_SMPR1_SMP15; /* Standard sequence. Measure all channels in one sequence */ - SAFETY_ADC_ADC_PERIPHERAL->SQR1 = (SAFETY_ADC_NUM_OF_CHANNELS - 1) << 20 ; + SAFETY_ADC_ADC_PERIPHERAL->SQR1 = (SAFETY_ADC_NUM_OF_CHANNELS - 1) << 20; SAFETY_ADC_ADC_PERIPHERAL->SQR2 = 0UL; SAFETY_ADC_ADC_PERIPHERAL->SQR3 = 0UL; @@ -97,7 +98,8 @@ void safety_adc_init(void) DMA2_Stream4->PAR = (uint32_t)&SAFETY_ADC_ADC_PERIPHERAL->DR; DMA2_Stream4->M0AR = (uint32_t)safety_adc_conversions; DMA2_Stream4->NDTR = SAFETY_ADC_NUM_OF_CHANNELS; - DMA2_Stream4->CR = DMA_SxCR_PL_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_CIRC | DMA_SxCR_TCIE | DMA_SxCR_EN; + DMA2_Stream4->CR = DMA_SxCR_PL_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_CIRC | + DMA_SxCR_TCIE | DMA_SxCR_EN; NVIC_EnableIRQ(DMA2_Stream4_IRQn); /* Enable ADC */ @@ -175,7 +177,7 @@ void safety_adc_trigger_meas(void) safety_adc_triggered = 1; } -void DMA2_Stream4_IRQHandler() +void DMA2_Stream4_IRQHandler(void) { uint32_t hisr; diff --git a/stm-firmware/safety/safety-controller.c b/stm-firmware/safety/safety-controller.c index e73aa88..eeaf7f7 100644 --- a/stm-firmware/safety/safety-controller.c +++ b/stm-firmware/safety/safety-controller.c @@ -1,28 +1,29 @@ /* Reflow Oven Controller -* -* Copyright (C) 2020 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 . -*/ + * + * Copyright (C) 2020 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 . + */ /** * @addtogroup safety-controller * @{ */ +#include "stm32/stm32f407xx.h" #include #include #include @@ -43,6 +44,7 @@ #include #include #include +#include #include /** @@ -154,15 +156,6 @@ struct overtemp_config { uint32_t crc; }; -struct flash_crcs { - uint32_t start_magic; - uint32_t crc_section_text; - uint32_t crc_section_data; - uint32_t crc_section_ccm_data; - uint32_t crc_section_vectors; - uint32_t end_magic; -}; - struct crc_monitor_register { const volatile void *reg_addr; uint32_t mask; @@ -171,9 +164,15 @@ struct crc_monitor_register { #define CRC_MON_REGISTER_ENTRY(_addr, _mask, _size) {.reg_addr = &(_addr), .mask = (_mask), .size = (_size)} +/** + * @brief Sentinel Element for crc monitor register list + * + */ +#define CRC_MON_REGISTER_SENTINEL {.reg_addr = NULL, .mask = 0, .size = 0} + struct crc_mon { /** - * @brief Array of registers to monitor. Terminated by NULL sentinel! + * @brief Array of registers to monitor. Terminated by NULL sentinel @ref CRC_MON_REGISTER_SENTINEL */ const struct crc_monitor_register *registers; const enum crc_monitor monitor; @@ -212,11 +211,12 @@ static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = { ERR_FLAG_ENTRY(ERR_FLAG_FLASH_CRC_DATA), ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC), ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC), + ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_MISC), }; /** - * @brief All timing monitors - */ + * @brief All timing monitors + */ static volatile struct timing_mon IN_SECTION(.ccm.data) timings[] = { TIM_MON_ENTRY(ERR_TIMING_PID, 2, 5000, ERR_FLAG_TIMING_PID), TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 0, 50, ERR_FLAG_TIMING_MEAS_ADC), @@ -298,8 +298,8 @@ static const struct crc_monitor_register meas_adc_crc_regs[] = { ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 | ADC_SQR2_SQ9 | ADC_SQR2_SQ8 | ADC_SQR2_SQ7, 4), CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SQR3, ADC_SQR3_SQ6 | ADC_SQR3_SQ5 | ADC_SQR3_SQ4 | - ADC_SQR3_SQ3| ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4), - {NULL, 0, 0} + ADC_SQR3_SQ3 | ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4), + CRC_MON_REGISTER_SENTINEL }; static const struct crc_monitor_register safety_adc_crc_regs[] = { @@ -314,12 +314,28 @@ static const struct crc_monitor_register safety_adc_crc_regs[] = { ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 | ADC_SQR2_SQ9 | ADC_SQR2_SQ8 | ADC_SQR2_SQ7, 4), CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SQR3, ADC_SQR3_SQ6 | ADC_SQR3_SQ5 | ADC_SQR3_SQ4 | - ADC_SQR3_SQ3| ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4), - {NULL, 0, 0} + ADC_SQR3_SQ3 | ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4), + CRC_MON_REGISTER_ENTRY(RCC->APB2ENR, SAFETY_ADC_ADC_RCC_MASK, 4), + CRC_MON_REGISTER_SENTINEL }; -static struct crc_mon IN_SECTION(.ccm.data) crc_monitors[] = -{ +static const struct crc_monitor_register misc_config_crc_regs[] = { + /* Check clock tree settings */ + CRC_MON_REGISTER_ENTRY(RCC->CR, RCC_CR_PLLON | RCC_CR_HSEON | RCC_CR_PLLI2SON | RCC_CR_HSION, 4), + CRC_MON_REGISTER_ENTRY(RCC->CSR, RCC_CSR_LSION, 4), + CRC_MON_REGISTER_ENTRY(RCC->CFGR, RCC_CFGR_SWS | RCC_CFGR_HPRE | RCC_CFGR_PPRE1 | RCC_CFGR_PPRE2, 4), + CRC_MON_REGISTER_ENTRY(RCC->PLLCFGR, RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLQ | RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLP | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLM , 4), + /* Check Flash settings */ + CRC_MON_REGISTER_ENTRY(FLASH->ACR, FLASH_ACR_LATENCY | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_PRFTEN, 4), + /* Check vector table offset */ + CRC_MON_REGISTER_ENTRY(SCB->VTOR, 0xFFFFFFFF, 4), + /* Check system tick configuration */ + CRC_MON_REGISTER_ENTRY(SysTick->CTRL, SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk, 4), + CRC_MON_REGISTER_ENTRY(SysTick->LOAD, 0xFFFFFFFF, 4), + CRC_MON_REGISTER_SENTINEL +}; + +static struct crc_mon IN_SECTION(.ccm.data) crc_monitors[] = { { .registers = meas_adc_crc_regs, .monitor = ERR_CRC_MON_MEAS_ADC, @@ -340,6 +356,16 @@ static struct crc_mon IN_SECTION(.ccm.data) crc_monitors[] = .last_crc = 0UL, .active = false, }, + { + .registers = misc_config_crc_regs, + .monitor = ERR_CRC_MON_MISC, + .pw = SAFETY_CRC_MON_MISC_PW, + .flag_to_set = ERR_FLAG_CFG_CRC_MISC, + .expected_crc = 0UL, + .expected_crc_inv = ~0UL, + .last_crc = 0UL, + .active = false, + } }; /** @@ -360,16 +386,22 @@ static void set_overtemp_config(float over_temperature) safety_controller_overtemp_config.crc_dummy_seed = 0xA4F5C7E6UL; safety_controller_overtemp_config.overtemp_deg_celsius = over_temperature; safety_controller_overtemp_config.overtemp_equiv_resistance = resistance; - crc_unit_input_array((const uint32_t *)&safety_controller_overtemp_config, wordsize_of(struct overtemp_config) - 1); + crc_unit_input_array((const uint32_t *)&safety_controller_overtemp_config, + wordsize_of(struct overtemp_config) - 1); safety_controller_overtemp_config.crc = crc_unit_get_crc(); } +/** + * @brief Check the overtemperature config structure's CRC + * @return true if check failed. false if CRC check successful + */ static bool over_temperature_config_check(void) { if (safety_controller_overtemp_config.crc_dummy_seed != 0xA4F5C7E6UL) return true; crc_unit_reset(); - crc_unit_input_array((const uint32_t *)&safety_controller_overtemp_config, wordsize_of(struct overtemp_config) - 1); + crc_unit_input_array((const uint32_t *)&safety_controller_overtemp_config, + wordsize_of(struct overtemp_config) - 1); if (crc_unit_get_crc() != safety_controller_overtemp_config.crc) return true; @@ -442,7 +474,7 @@ static int flag_weight_table_crc_check(void) static int flag_persistence_table_crc_check(void) { crc_unit_reset(); - crc_unit_input_array((uint32_t*)flag_persistencies, wordsize_of(flag_persistencies)); + crc_unit_input_array((uint32_t *)flag_persistencies, wordsize_of(flag_persistencies)); if (crc_unit_get_crc() != flag_persistencies_crc) return -1; @@ -519,9 +551,8 @@ static int safety_controller_check_crc_monitors(void) if (crc_monitor_calculate_crc(mon->registers, &crc)) return -1; - if (mon->expected_crc != crc || ~mon->expected_crc_inv != crc) { + if (mon->expected_crc != crc || ~mon->expected_crc_inv != crc) safety_controller_report_error(mon->flag_to_set); - } mon->last_crc = crc; } @@ -548,7 +579,7 @@ static void init_safety_flag_weight_table_from_default(void) } crc_unit_reset(); - crc_unit_input_array((uint32_t*)flag_weights, wordsize_of(flag_weights)); + crc_unit_input_array((uint32_t *)flag_weights, wordsize_of(flag_weights)); flag_weight_crc = crc_unit_get_crc(); } @@ -608,16 +639,14 @@ static void apply_config_overrides(void) case SAFETY_MEMORY_CONFIG_OVERRIDE_WEIGHT: flag_enum = flag_no_to_flag_enum(override.entry.weight_override.flag); flag = find_error_flag(flag_enum); - if (flag && flag->weight) { + if (flag && flag->weight) flag->weight->weight = override.entry.weight_override.weight; - } break; case SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE: flag_enum = flag_no_to_flag_enum(override.entry.persistence_override.flag); flag = find_error_flag(flag_enum); - if (flag && flag->persistence) { + if (flag && flag->persistence) flag->persistence->persistence = override.entry.persistence_override.persistence; - } break; default: continue; @@ -629,7 +658,7 @@ static void apply_config_overrides(void) crc_unit_input_array((uint32_t *)flag_persistencies, wordsize_of(flag_persistencies)); flag_persistencies_crc = crc_unit_get_crc(); crc_unit_reset(); - crc_unit_input_array((uint32_t*)flag_weights, wordsize_of(flag_weights)); + crc_unit_input_array((uint32_t *)flag_weights, wordsize_of(flag_weights)); flag_weight_crc = crc_unit_get_crc(); } @@ -647,11 +676,10 @@ static bool error_flag_get_status(const volatile struct error_flag *flag) if (!flag) return true; - if (flag->error_state == flag->error_state_inv) { + if (flag->error_state == flag->error_state_inv) return true; - } else { + else return flag->error_state; - } } /** @@ -693,7 +721,7 @@ static volatile struct timing_mon *find_timing_mon(enum timing_monitor mon) /** * @brief Check the active timing monitors and set the appropriate flags in case of an error. */ -static void safety_controller_process_active_timing_mons() +static void safety_controller_process_active_timing_mons(void) { uint32_t i; volatile struct timing_mon *current_mon; @@ -716,7 +744,8 @@ static void safety_controller_process_active_timing_mons() * Process the analog and timing monitors and set the relevant flags in case of a monitor outside its limits. * Furthermore, the PT1000 resistance is checked for overtemperature * - * The checking of the analog monitors will only be armed after a startup delay of 1000 ms to allow the values to stabilize. + * The checking of the analog monitors will only be armed after a startup delay of 1000 ms to + * allow the values to stabilize. */ static void safety_controller_process_monitor_checks(void) { @@ -731,21 +760,18 @@ static void safety_controller_process_monitor_checks(void) if (startup_completed) { analog_mon_count = safety_controller_get_analog_monitor_count(); - for (idx = 0; idx < analog_mon_count; idx++) { + for (idx = 0; idx < analog_mon_count; idx++) if (safety_controller_get_analog_mon_by_index(idx, &amon_info)) { panic_mode(); - } - if (amon_info.status != ANALOG_MONITOR_OK) { + if (amon_info.status != ANALOG_MONITOR_OK) safety_controller_report_error(amon_info.associated_flag); - } } } adc_pt1000_get_current_resistance(&pt1000_val); - if (pt1000_val > safety_controller_overtemp_config.overtemp_equiv_resistance) { + if (pt1000_val > safety_controller_overtemp_config.overtemp_equiv_resistance) safety_controller_report_error(ERR_FLAG_OVERTEMP); - } (void)safety_controller_check_crc_monitors(); @@ -779,7 +805,7 @@ static int report_error(enum safety_flag flag, uint32_t key, bool prevent_error_ flags[i].error_state_inv = !flags[i].error_state; flags[i].key = key; - if ((check_flag_persistent(&flags[i]) && !old_state && !prevent_error_mem_enty) || + if ((check_flag_persistent(&flags[i]) && !old_state && !prevent_error_mem_enty) || get_flag_weight(&flags[i]) == SAFETY_FLAG_CONFIG_WEIGHT_PANIC) { err_mem_entry.counter = 1; err_mem_entry.flag_num = flag_enum_to_flag_no(flags[i].flag); @@ -820,9 +846,8 @@ void safety_controller_report_timing(enum timing_monitor monitor) tim = find_timing_mon(monitor); if (tim) { if (tim->enabled) { - if (!systick_ticks_have_passed(tim->last, tim->min_delta) && tim->min_delta > 0U) { + if (!systick_ticks_have_passed(tim->last, tim->min_delta) && tim->min_delta > 0U) safety_controller_report_error(tim->associated_flag); - } } tim->calculated_delta = timestamp - tim->last; @@ -870,9 +895,8 @@ static int get_safety_flags_from_error_mem(enum safety_flag *flags) for (idx = 0; idx < count; idx++) { res = safety_memory_get_error_entry(idx, &entry); - if (entry.type == SAFETY_MEMORY_ERR_ENTRY_FLAG) { + if (entry.type == SAFETY_MEMORY_ERR_ENTRY_FLAG) return_flags |= flag_no_to_flag_enum(entry.flag_num); - } } *flags = return_flags; @@ -884,11 +908,12 @@ static int get_safety_flags_from_error_mem(enum safety_flag *flags) * * The external harware watchdog has to be periodically reset or it will reset hte controller. * Because debugging is not possible, when the watchdog is active, it is only activated, if the application is - * compiled in release mode. Any interruption of the main programm will then trigger the internal and/or the external watchdog. + * compiled in release mode. Any interruption of the main programm will then trigger the internal and/or + * the external watchdog. * * @note When enabled, execute the @ref external_watchdog_toggle function to reset the external watchdog. */ -static void safety_controller_init_external_watchdog() +static void safety_controller_init_external_watchdog(void) { rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(SAFETY_EXT_WATCHDOG_RCC_MASK)); SAFETY_EXT_WATCHDOG_PORT->MODER &= MODER_DELETE(SAFETY_EXT_WATCHDOG_PIN); @@ -899,7 +924,7 @@ static void safety_controller_init_external_watchdog() __DSB(); } -void safety_controller_init() +void safety_controller_init(void) { enum safety_memory_state found_memory_state; enum safety_flag flags_in_err_mem = ERR_FLAG_NO_FLAG; @@ -916,7 +941,7 @@ void safety_controller_init() /* This is usually done by the safety memory already. But, since this module also uses the CRC... */ crc_unit_init(); - safety_controller_trigger_flash_crc_check(); + flash_crc_trigger_check(); stack_check_init_corruption_detect_area(); hw_rev = get_pcb_hardware_version(); @@ -948,7 +973,7 @@ void safety_controller_init() MEAS_ADC_SAFETY_FLAG_KEY); safety_adc_init(); - watchdog_setup(WATCHDOG_PRESCALER); + (void)watchdog_setup(WATCHDOG_PRESCALER, WATCHDOG_RELOAD_VALUE); if (rcc_manager_get_reset_cause(false) & RCC_RESET_SOURCE_IWDG) safety_controller_report_error(ERR_FLAG_WTCHDG_FIRED); @@ -967,7 +992,7 @@ void safety_controller_init() * 1) Checking the remaining free space at the moment between stack pointer and top of heap. * 2) Checking The CRC of the corruption detect area between heap and stack */ -static void safety_controller_check_stack() +static void safety_controller_check_stack(void) { int32_t free_stack; @@ -975,18 +1000,17 @@ static void safety_controller_check_stack() if (free_stack < SAFETY_MIN_STACK_FREE) safety_controller_report_error(ERR_FLAG_STACK); - if (stack_check_corruption_detect_area()) { + if (stack_check_corruption_detect_area()) safety_controller_report_error(ERR_FLAG_STACK); - } } /** * @brief Handle the Safety ADC * * This function handles the safety ADC. - * If the safety ADC ius not executing a measurment and the time since the last measurement has - * passed @ref SAFETY_CONTROLLER_ADC_DELAY_MS, the safety ADC is retriggered and will automatically perform a measurement - * on all of its channels. + * If the safety ADC is not executing a measurment and the time since the last measurement has + * passed @ref SAFETY_CONTROLLER_ADC_DELAY_MS, the safety ADC is retriggered and will automatically perform a + * measurement on all of its channels. * When called again, this function will retrieve the data from the safety ADC and converts it into the * appropriate analog values for the analog value monitors. * @@ -995,7 +1019,7 @@ static void safety_controller_check_stack() * * The channels, the ssafety ADC will convert is defined in its header file using the define @ref SAFETY_ADC_CHANNELS. */ -static void safety_controller_handle_safety_adc() +static void safety_controller_handle_safety_adc(void) { static uint64_t last_result_timestamp = 0; const uint16_t *channels; @@ -1066,9 +1090,8 @@ static void safety_controller_handle_memory_checks(void) /* Check the safety memory */ if (safety_memory_check()) { (void)safety_memory_reinit(&found_state); - if (found_state != SAFETY_MEMORY_INIT_VALID_MEMORY) { + if (found_state != SAFETY_MEMORY_INIT_VALID_MEMORY) safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT); - } } /* If flag weight table is broken, reinit to default and set flag */ @@ -1078,7 +1101,7 @@ static void safety_controller_handle_memory_checks(void) } /* If persistence table is broken, reinit to default and set flag */ - if(flag_persistence_table_crc_check()) { + if (flag_persistence_table_crc_check()) { safety_controller_report_error(ERR_FLAG_SAFETY_TAB_CORRUPT); init_safety_flag_persistencies_from_default(); } @@ -1097,7 +1120,7 @@ static void safety_controller_handle_memory_checks(void) * If the systick stays constant for more than 1000 calls of this function, * the @ref ERR_FLAG_SYSTICK flag is set. */ -static void safety_controller_do_systick_checking() +static void safety_controller_do_systick_checking(void) { static uint64_t last_systick; static uint32_t same_systick_cnt = 0UL; @@ -1121,22 +1144,29 @@ static void safety_controller_do_systick_checking() * is set, the appropriate action defined by the flag weight is executed. * @note If no flag weigth is present for a given error flag, it is treated as the most critical category * (@ref SAFETY_FLAG_CONFIG_WEIGHT_PANIC) + * + * @returns Worst config weight set */ -static void safety_controller_handle_weighted_flags() +static enum config_weight safety_controller_handle_weighted_flags(void) { uint32_t flag_index; volatile struct error_flag *current_flag; enum config_weight flag_weigth; + enum config_weight worst = SAFETY_FLAG_CONFIG_WEIGHT_NONE; for (flag_index = 0u; flag_index < COUNT_OF(flags); flag_index++) { current_flag = &flags[flag_index]; /* Continue if this flag is not set */ - if (!error_flag_get_status(current_flag)) { + if (!error_flag_get_status(current_flag)) continue; - } flag_weigth = get_flag_weight(current_flag); + + /* Override the worst flag weigt set, if it is worse than the previous ones */ + if (flag_weigth > worst) + worst = flag_weigth; + switch (flag_weigth) { case SAFETY_FLAG_CONFIG_WEIGHT_NONE: break; @@ -1152,18 +1182,20 @@ static void safety_controller_handle_weighted_flags() } } + + return worst; } #ifndef DEBUGBUILD -static void external_watchdog_toggle() +static void external_watchdog_toggle(void) { SAFETY_EXT_WATCHDOG_PORT->ODR ^= (1<= COUNT_OF(timings)) { + if (index >= COUNT_OF(timings)) return -1001; - } mon = &timings[index]; @@ -1449,99 +1481,6 @@ float safety_controller_get_overtemp_limit(void) return safety_controller_overtemp_config.overtemp_deg_celsius; } -extern const uint32_t __ld_vectors_start; -extern const uint32_t __ld_vectors_end; -extern const uint32_t __ld_text_start; -extern const uint32_t __ld_text_end; - -extern const uint32_t __ld_sdata_ccm; -extern const uint32_t __ld_edata_ccm; -extern const uint32_t __ld_load_ccm_data; - -extern const uint32_t __ld_sdata; -extern const uint32_t __ld_edata; -extern const uint32_t __ld_load_data; - -int safety_controller_trigger_flash_crc_check() -{ - /* This structs needs to be volatile!! - * This prevents the compiler form optimizing out the reads to the crcs which will be patched in later by - * a separate python script! - */ - static volatile const struct flash_crcs IN_SECTION(.flashcrc) crcs_in_flash = - { - .start_magic = 0xA8BE53F9UL, - .crc_section_ccm_data = 0UL, - .crc_section_text = 0UL, - .crc_section_data = 0UL, - .crc_section_vectors = 0UL, - .end_magic = 0xFFA582FFUL, - }; - - int ret = -1; - uint32_t len; - uint32_t crc; - - /* Perform CRC check over vector table */ - len = (uint32_t)((void *)&__ld_vectors_end - (void *)&__ld_vectors_start); - if (len % 4) { - safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE); - } else { - len /= 4; - crc_unit_reset(); - crc_unit_input_array(&__ld_vectors_start, len); - crc = crc_unit_get_crc(); - if (crc != crcs_in_flash.crc_section_vectors) { - safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE); - } - } - - /* Perform CRC check over text section */ - len = (uint32_t)((void *)&__ld_text_end - (void *)&__ld_text_start); - if (len % 4) { - safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE); - } else { - len /= 4; - crc_unit_reset(); - crc_unit_input_array(&__ld_text_start, len); - crc = crc_unit_get_crc(); - if (crc != crcs_in_flash.crc_section_text) { - safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE); - } - } - - /* Perform CRC check over data section */ - len = (uint32_t)((void *)&__ld_edata - (void *)&__ld_sdata); - if (len % 4) { - safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA); - } else { - len /= 4; - crc_unit_reset(); - crc_unit_input_array(&__ld_load_data, len); - crc = crc_unit_get_crc(); - if (crc != crcs_in_flash.crc_section_data) { - safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA); - } - } - - /* Perform CRC check over ccm data section */ - len = (uint32_t)((void *)&__ld_edata_ccm - (void *)&__ld_sdata_ccm); - if (len % 4) { - safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA); - } else { - len /= 4; - crc_unit_reset(); - crc_unit_input_array(&__ld_load_ccm_data, len); - crc = crc_unit_get_crc(); - if (crc != crcs_in_flash.crc_section_ccm_data) { - safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA); - } - } - - ret = 0; - return ret; -} - int safety_controller_set_crc_monitor(enum crc_monitor mon, uint32_t password) { uint32_t i; diff --git a/stm-firmware/safety/safety-memory.c b/stm-firmware/safety/safety-memory.c index bcb26bd..775820a 100644 --- a/stm-firmware/safety/safety-memory.c +++ b/stm-firmware/safety/safety-memory.c @@ -1,22 +1,22 @@ /* Reflow Oven Controller -* -* Copyright (C) 2020 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 . -*/ + * + * Copyright (C) 2020 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 @@ -99,7 +99,8 @@ static enum safety_memory_state safety_memory_get_header(struct safety_memory_he res = 0; if (header->boot_status_offset < wordsize_of(struct safety_memory_header)) res++; - if (header->config_overrides_offset < header->boot_status_offset + wordsize_of(struct safety_memory_boot_status)) + if (header->config_overrides_offset < header->boot_status_offset + + wordsize_of(struct safety_memory_boot_status)) res++; if (header->config_overrides_len > SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT) res++; @@ -107,7 +108,8 @@ static enum safety_memory_state safety_memory_get_header(struct safety_memory_he res++; if (header->err_memory_offset < header->firmware_update_filename + (SAFETY_MEMORY_UPDATE_FILENAME_MAXSIZE / 4)) res++; - if (header->err_memory_end >= backup_ram_get_size_in_words() || header->err_memory_end < header->err_memory_offset) + if (header->err_memory_end >= backup_ram_get_size_in_words() || + header->err_memory_end < header->err_memory_offset) res++; if (res) { @@ -148,7 +150,7 @@ static void safety_memory_write_new_header(void) safety_memory_write_and_patch_header(&header); } -static int safety_memory_check_crc() +static int safety_memory_check_crc(void) { struct safety_memory_header header; enum safety_memory_state state = safety_memory_get_header(&header); @@ -181,7 +183,7 @@ static int safety_memory_check_crc() return 0; } -static int safety_memory_gen_crc() +static int safety_memory_gen_crc(void) { struct safety_memory_header header; uint32_t word_addr; @@ -268,9 +270,8 @@ int safety_memory_get_boot_status(struct safety_memory_boot_status *status) if (!status) return -1001; - if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { + if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) return -2000; - } if (safety_memory_check_crc()) return -2001; @@ -289,9 +290,8 @@ int safety_memory_set_boot_status(const struct safety_memory_boot_status *status if (!status) return -1001; - if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { + if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) return -2000; - } if (safety_memory_check_crc()) return -2001; @@ -304,7 +304,7 @@ int safety_memory_set_boot_status(const struct safety_memory_boot_status *status return 0; } -static int safety_memory_check_error_entries() +static int safety_memory_check_error_entries(void) { struct safety_memory_header header; uint32_t addr; @@ -312,9 +312,8 @@ static int safety_memory_check_error_entries() int ret = 0; int res; - if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { + if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) return -2000; - } for (addr = header.err_memory_offset; addr < header.err_memory_end; addr++) { res = backup_ram_get_data(addr, &data, 1UL); @@ -340,9 +339,8 @@ int safety_memory_get_error_entry_count(uint32_t *count) if (!count) return -1001; - if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { + if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) return -2000; - } *count = header.err_memory_end - header.err_memory_offset; @@ -354,9 +352,8 @@ int safety_memory_check(void) int res; res = safety_memory_check_crc(); - if (!res) { + if (!res) res |= safety_memory_check_error_entries(); - } return -!!res; } @@ -372,9 +369,8 @@ int safety_memory_get_error_entry(uint32_t idx, struct error_memory_entry *entry if (!entry) return -1001; - if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { + if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) return -2000; - } err_mem_count = header.err_memory_end - header.err_memory_offset; if (idx < err_mem_count && err_mem_count > 0) { @@ -410,9 +406,8 @@ int safety_memory_insert_error_entry(struct error_memory_entry *entry) input_data = error_memory_entry_to_word(entry); - if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { + if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) return -2000; - } if (entry->type == SAFETY_MEMORY_ERR_ENTRY_NOP) { /* Append to end */ @@ -510,9 +505,8 @@ int safety_memory_insert_config_override(struct config_override *config_override int res; int ret = -3; - if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { + if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) return -2000; - } if (header.config_overrides_len == 0) return -1; @@ -550,9 +544,8 @@ int safety_memory_get_config_override_count(uint32_t *count) *count = 0UL; - if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { + if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) return -2000; - } if (header.config_overrides_len == 0) return 0; @@ -582,18 +575,15 @@ int safety_memory_get_config_override(uint32_t idx, struct config_override *conf if (!config_override) return -1002; - if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { + if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) return -2000; - } - if (idx >= header.config_overrides_len) { + if (idx >= header.config_overrides_len) return -1001; - } res = backup_ram_get_data(header.config_overrides_offset + idx, &data, 1UL); - if (res) { + if (res) return -1; - } switch (data & 0xFF) { case 0xA2: @@ -649,8 +639,8 @@ int safety_memory_get_update_filename(char *filename, size_t *outlen) { struct safety_memory_header header; unsigned int i; - volatile char *ptr; size_t len = 0u; + volatile char *ptr; /* If filename and outlen are both NULL, we don't do anything */ if (!filename && !outlen) @@ -696,9 +686,9 @@ int safety_memory_set_update_filename(const char *filename) ram_ptr = backup_ram_get_base_ptr(); ram_ptr += header.firmware_update_filename * 4; - for (i = 0u; i < len; i++) { + for (i = 0u; i < len; i++) ram_ptr[i] = filename[i]; - } + ram_ptr[i] = 0; ret = safety_memory_gen_crc(); diff --git a/stm-firmware/safety/stack-check.c b/stm-firmware/safety/stack-check.c index 9940c8c..bdf449e 100644 --- a/stm-firmware/safety/stack-check.c +++ b/stm-firmware/safety/stack-check.c @@ -1,22 +1,22 @@ /* Reflow Oven Controller -* -* Copyright (C) 2020 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 . -*/ + * + * Copyright (C) 2020 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 @@ -26,7 +26,7 @@ extern char __ld_top_of_stack; extern char __ld_end_stack; -int32_t stack_check_get_usage() +int32_t stack_check_get_usage(void) { uint32_t stack_top; uint32_t stack_ptr; @@ -37,7 +37,7 @@ int32_t stack_check_get_usage() return stack_top - stack_ptr; } -int32_t stack_check_get_free() +int32_t stack_check_get_free(void) { uint32_t upper_heap_boundary; uint32_t stack_ptr; @@ -102,9 +102,6 @@ int stack_check_corruption_detect_area(void) &__ld_start_stack_corruption_detect_area; crc_unit_reset(); crc_unit_input_array(&__ld_start_stack_corruption_detect_area, area_size_in_words); - if (crc_unit_get_crc() == 0UL) { - return 0; - } else { - return -1; - } + + return crc_unit_get_crc() == 0UL ? 0 : -1; } diff --git a/stm-firmware/safety/watchdog.c b/stm-firmware/safety/watchdog.c index d4f318b..1147b8f 100644 --- a/stm-firmware/safety/watchdog.c +++ b/stm-firmware/safety/watchdog.c @@ -1,22 +1,22 @@ /* Reflow Oven Controller -* -* Copyright (C) 2020 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 . -*/ + * + * Copyright (C) 2020 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 . + */ /** * @addtogroup watchdog @@ -42,52 +42,63 @@ */ #define STM32_WATCHDOG_REGISTER_ACCESS_KEY 0x5555 -int watchdog_setup(uint8_t prescaler) +int watchdog_setup(uint16_t prescaler, uint16_t reload_value) { uint32_t prescaler_reg_val; + int ret = 0; /** - Activate the LSI oscillator */ RCC->CSR |= RCC_CSR_LSION; __DSB(); /** - Wait for the oscillator to be ready */ - while (!(RCC->CSR & RCC_CSR_LSIRDY)); + while (!(RCC->CSR & RCC_CSR_LSIRDY)) + ; - if (prescaler == 4U) + if (prescaler == 4U) { prescaler_reg_val = 0UL; - else if (prescaler == 8U) + } else if (prescaler == 8U) { prescaler_reg_val = 1UL; - else if (prescaler == 16U) + } else if (prescaler == 16U) { prescaler_reg_val = 2UL; - else if (prescaler == 32U) + } else if (prescaler == 32U) { prescaler_reg_val = 3UL; - else if (prescaler == 64U) + } else if (prescaler == 64U) { prescaler_reg_val = 4UL; - else if (prescaler == 128U) + } else if (prescaler == 128U) { prescaler_reg_val = 5UL; - else + } else if (prescaler == 256U) { prescaler_reg_val = 6UL; + } else { + prescaler_reg_val = 6UL; + ret = -1; + } /** - (De)activate the watchdog during debug access according to @ref WATCHDOG_HALT_DEBUG */ - if (WATCHDOG_HALT_DEBUG) { + if (WATCHDOG_HALT_DEBUG) DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_IWDG_STOP; - } else { + else DBGMCU->APB1FZ &= ~DBGMCU_APB1_FZ_DBG_IWDG_STOP; - } /** - Unlock registers */ IWDG->KR = STM32_WATCHDOG_REGISTER_ACCESS_KEY; /** - Wait until prescaler can be written */ - while (IWDG->SR & IWDG_SR_PVU); + while (IWDG->SR & IWDG_SR_PVU) + ; /** - Write prescaler value */ IWDG->PR = prescaler_reg_val; /* - Wait until reload value can be written */ - while (IWDG->SR & IWDG_SR_RVU); + while (IWDG->SR & IWDG_SR_RVU) + ; - /** - Set reload value fixed to 0xFFF */ - IWDG->RLR = 0xFFFU; + /** - Set reload value */ + if (reload_value > 0xFFFu) { + reload_value = 0xFFFFu; + ret = -2; + } + IWDG->RLR = reload_value; /** - Write enable key */ IWDG->KR = STM32_WATCHDOG_ENABLE_KEY; @@ -95,7 +106,7 @@ int watchdog_setup(uint8_t prescaler) /** - Do a first reset of the counter. This also locks the config regs */ watchdog_ack(WATCHDOG_MAGIC_KEY); - return 0; + return ret; } int watchdog_ack(uint32_t magic) diff --git a/stm-firmware/sd.c b/stm-firmware/sd.c new file mode 100644 index 0000000..eee16e2 --- /dev/null +++ b/stm-firmware/sd.c @@ -0,0 +1,65 @@ +/* Reflow Oven Controller + * + * Copyright (C) 2022 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. + * + * GDSII-Converter 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 "fatfs/ff.h" +#include "fatfs/shimatta_sdio_driver/shimatta_sdio.h" +#include +#include +#include +#include + +static bool sd_card_mounted_state = false; + +bool mount_sd_card_if_avail(FATFS *fs) +{ + FRESULT res; + static uint8_t IN_SECTION(.ccm.bss) inserted_counter = 0; + + if (sdio_check_inserted() && sd_card_mounted_state) { + memset(fs, 0, sizeof(FATFS)); + sdio_stop_clk(); + inserted_counter = 0; + sd_card_mounted_state = false; + goto ret; + } + + if (!sdio_check_inserted() && inserted_counter < 255) + inserted_counter++; + + if (!sdio_check_inserted() && !sd_card_mounted_state && inserted_counter > 4) { + inserted_counter = 0; + res = f_mount(fs, "0:/", 1); + if (res == FR_OK) { + led_set(1, 1); + sd_card_mounted_state = true; + } else { + sd_card_mounted_state = false; + } + } + +ret: + return sd_card_mounted_state; +} + +bool sd_card_is_mounted(void) +{ + return sd_card_mounted_state; +} \ No newline at end of file diff --git a/stm-firmware/settings/settings-eeprom.c b/stm-firmware/settings/settings-eeprom.c index 974fb97..60041f1 100644 --- a/stm-firmware/settings/settings-eeprom.c +++ b/stm-firmware/settings/settings-eeprom.c @@ -1,22 +1,22 @@ /* Reflow Oven Controller -* -* Copyright (C) 2020 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 . -*/ + * + * Copyright (C) 2020 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 @@ -37,6 +37,7 @@ struct eeprom_calibration_settings { }; #define EEPROM_OVER_TEMP_CONFIG_BASE_ADDR (EEPROM_CALIBRATION_BASE_ADDR + sizeof(struct eeprom_calibration_settings)) + struct eeprom_over_temp_config { float over_temperature; uint32_t over_temp_crc; @@ -54,7 +55,7 @@ static bool check_eeprom_header(void) return true; } -static void settings_eeprom_zero() +static void settings_eeprom_zero(void) { settings_eeprom_save_calibration(0.0f, 0.0f, false); settings_eeprom_save_overtemp_limit(0.0f, false); @@ -62,7 +63,7 @@ static void settings_eeprom_zero() bool settings_eeprom_detect_and_prepare(void) { - bool eeprom_ready = false;; + bool eeprom_ready = false; int res; @@ -77,7 +78,10 @@ bool settings_eeprom_detect_and_prepare(void) if (check_eeprom_header() == false) { /* Try to write a new header and check it again */ spi_eeprom_write(0, expected_header, sizeof(expected_header)); - while (spi_eeprom_write_in_progress()); + + while (spi_eeprom_write_in_progress()) + ; + if (check_eeprom_header() == false) { goto ret_deinit_crc; } else { diff --git a/stm-firmware/settings/settings-sd-card.c b/stm-firmware/settings/settings-sd-card.c index bf1a5bd..3fd5c8b 100644 --- a/stm-firmware/settings/settings-sd-card.c +++ b/stm-firmware/settings/settings-sd-card.c @@ -1,22 +1,22 @@ /* Reflow Oven Controller -* -* Copyright (C) 2020 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 . -*/ + * + * Copyright (C) 2020 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 @@ -72,18 +72,12 @@ static int create_controller_folder(void) ret = 0; } else { filesystem_result = f_mkdir(foldername); - if (filesystem_result == FR_OK) { - ret = 1; - } else { - ret = -1; - } + ret = filesystem_result == FR_OK ? 1 : -1; } return ret; } - - int sd_card_settings_save_calibration(float sens_deviation, float offset, bool active) { char path[200]; diff --git a/stm-firmware/settings/settings.c b/stm-firmware/settings/settings.c index 09d2ae8..a21f3e9 100644 --- a/stm-firmware/settings/settings.c +++ b/stm-firmware/settings/settings.c @@ -1,22 +1,22 @@ /* Reflow Oven Controller -* -* Copyright (C) 2020 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 . -*/ + * + * Copyright (C) 2020 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 @@ -39,7 +39,7 @@ int settings_load_calibration(float *sens_dev, float *offset) int res; if (settings_use_eeprom) { - res =settings_eeprom_load_calibration(sens_dev, offset, &active); + res = settings_eeprom_load_calibration(sens_dev, offset, &active); if (!res && !active) res = -1; } else { diff --git a/stm-firmware/settings/spi-eeprom.c b/stm-firmware/settings/spi-eeprom.c index 6a5ad63..ef19260 100644 --- a/stm-firmware/settings/spi-eeprom.c +++ b/stm-firmware/settings/spi-eeprom.c @@ -1,22 +1,22 @@ /* 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 . -*/ + * + * 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 @@ -52,7 +52,7 @@ static void eeprom_cs_deactivate(void) SPI_EEPROM_SPI_PORT->ODR |= (1<MODER &= MODER_DELETE(SPI_EEPROM_CS_PIN) & MODER_DELETE(SPI_EEPROM_MISO_PIN) & MODER_DELETE(SPI_EEPROM_MOSI_PIN) & MODER_DELETE(SPI_EEPROM_SCK_PIN); - SPI_EEPROM_SPI_PORT->MODER |= ALTFUNC(SPI_EEPROM_MISO_PIN) | ALTFUNC(SPI_EEPROM_SCK_PIN) | ALTFUNC(SPI_EEPROM_MOSI_PIN); + SPI_EEPROM_SPI_PORT->MODER |= ALTFUNC(SPI_EEPROM_MISO_PIN) | ALTFUNC(SPI_EEPROM_SCK_PIN) | + ALTFUNC(SPI_EEPROM_MOSI_PIN); SPI_EEPROM_SPI_PORT->MODER |= OUTPUT(SPI_EEPROM_CS_PIN); SETAF(SPI_EEPROM_SPI_PORT, SPI_EEPROM_MISO_PIN, SPI_EEPROM_SPI_ALTFUNC_NO); @@ -85,7 +86,7 @@ int spi_eeprom_init() return -1; } -void spi_eeprom_deinit() +void spi_eeprom_deinit(void) { spi_deinit(eeprom_spi_handle); @@ -166,7 +167,8 @@ static void spi_eeprom_do_write_page(uint32_t addr, const uint8_t *data, uint8_t uint8_t cmd[2]; /* Wait for the previous write to finish */ - while (spi_eeprom_write_in_progress()); + while (spi_eeprom_write_in_progress()) + ; /* Set the write enable latch */ spi_eeprom_set_write_enable_latch(true); diff --git a/stm-firmware/stm-periph/backup-ram.c b/stm-firmware/stm-periph/backup-ram.c index 6428fc2..8865d83 100644 --- a/stm-firmware/stm-periph/backup-ram.c +++ b/stm-firmware/stm-periph/backup-ram.c @@ -46,7 +46,8 @@ void backup_ram_init(bool use_backup_regulator) PWR->CSR |= PWR_CSR_BRE; /* Wait until regulator is ready */ - while (!(PWR->CSR & PWR_CSR_BRR)); + while (!(PWR->CSR & PWR_CSR_BRR)) + ; } /* Enable clock for backup ram interface */ diff --git a/stm-firmware/stm-periph/dma-ring-buffer.c b/stm-firmware/stm-periph/dma-ring-buffer.c index f359fd1..e0fc3b2 100644 --- a/stm-firmware/stm-periph/dma-ring-buffer.c +++ b/stm-firmware/stm-periph/dma-ring-buffer.c @@ -37,11 +37,10 @@ static size_t calculate_ring_buffer_fill_level(size_t buffer_size, size_t get_id { size_t fill_level; - if (put_idx >= get_idx) { + if (put_idx >= get_idx) fill_level = (put_idx - get_idx); - } else { + else fill_level = buffer_size - get_idx + put_idx; - } return fill_level; } @@ -49,7 +48,7 @@ static size_t calculate_ring_buffer_fill_level(size_t buffer_size, size_t get_id static int dma_ring_buffer_switch_clock_enable(uint8_t base_dma, bool clk_en) { int ret_val; - int (*clk_func)(volatile uint32_t *, uint8_t); + int (*clk_func)(volatile uint32_t *reg, uint8_t bit_no); if (clk_en) clk_func = rcc_manager_enable_clock; @@ -72,8 +71,9 @@ static int dma_ring_buffer_switch_clock_enable(uint8_t base_dma, bool clk_en) } int dma_ring_buffer_periph_to_mem_initialize(struct dma_ring_buffer_to_mem *dma_buffer, uint8_t base_dma_id, - DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size, - volatile void *data_buffer, void* src_reg, uint8_t dma_trigger_channel) + DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, + size_t element_size, volatile void *data_buffer, + void *src_reg, uint8_t dma_trigger_channel) { int ret_val = 0; @@ -106,7 +106,8 @@ int dma_ring_buffer_periph_to_mem_initialize(struct dma_ring_buffer_to_mem *dma_ return 0; } -int dma_ring_buffer_periph_to_mem_get_data(struct dma_ring_buffer_to_mem *buff, const volatile void **data_buff, size_t *len) +int dma_ring_buffer_periph_to_mem_get_data(struct dma_ring_buffer_to_mem *buff, const volatile void **data_buff, + size_t *len) { int ret_code = 0; uint32_t ndtr; @@ -167,7 +168,10 @@ int dma_ring_buffer_periph_to_mem_fill_level(struct dma_ring_buffer_to_mem *buff return 0; } -int dma_ring_buffer_mem_to_periph_initialize(struct dma_ring_buffer_to_periph *dma_buffer, uint8_t base_dma_id, DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size, volatile void *data_buffer, uint8_t dma_trigger_channel, void *dest_reg) +int dma_ring_buffer_mem_to_periph_initialize(struct dma_ring_buffer_to_periph *dma_buffer, uint8_t base_dma_id, + DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, + size_t element_size, volatile void *data_buffer, + uint8_t dma_trigger_channel, void *dest_reg) { if (!dma_buffer || !dma_stream || !data_buffer || !dest_reg) return -1000; @@ -221,7 +225,8 @@ static void queue_or_start_dma_transfer(struct dma_ring_buffer_to_periph *buff) buff->dma->CR |= DMA_SxCR_EN; } -int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *buff, const void *data_to_insert, size_t count) +int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *buff, const void *data_to_insert, + size_t count) { int ret = 0; size_t free_item_count; @@ -234,7 +239,8 @@ int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph * return -1000; /* Check if data fits into buffer minus one element. If not: try full-1 buffer and rest - * Buffer is not allowed to be completely full, because I cannot ddifferentiate a full buffer from a completely empty one + * Buffer is not allowed to be completely full, because I cannot ddifferentiate a full buffer from a + * completely empty one */ if (count >= buff->buffer_count) { ret = dma_ring_buffer_mem_to_periph_insert_data(buff, data_to_insert, buff->buffer_count - 1); @@ -247,7 +253,9 @@ int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph * /* Wait for buffer to be able to handle input */ do { - free_item_count = buff->buffer_count - calculate_ring_buffer_fill_level(buff->buffer_count, buff->dma_get_idx_current, buff->sw_put_idx); + free_item_count = buff->buffer_count - + calculate_ring_buffer_fill_level(buff->buffer_count, buff->dma_get_idx_current, + buff->sw_put_idx); } while (free_item_count < count+1); /* Fillup buffer (max is buffer end, wrap around afterwards) */ @@ -261,7 +269,7 @@ int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph * buff->sw_put_idx += count; /* If buffer is used up to last element, set put index to beginning */ - if(buff->sw_put_idx >= buff->buffer_count) + if (buff->sw_put_idx >= buff->buffer_count) buff->sw_put_idx = 0; } else { /* Fill up to end of buffer and fill rest after wrap around */ diff --git a/stm-firmware/stm-periph/option-bytes.c b/stm-firmware/stm-periph/option-bytes.c index 3425726..5f133c9 100644 --- a/stm-firmware/stm-periph/option-bytes.c +++ b/stm-firmware/stm-periph/option-bytes.c @@ -76,12 +76,14 @@ int stm_option_bytes_program(const struct option_bytes *opts) reg |= (opts->read_protection << 8) & FLASH_OPTCR_RDP; reg |= (opts->wdg_sw << 5) & FLASH_OPTCR_WDG_SW; - while (FLASH->SR & FLASH_SR_BSY); + while (FLASH->SR & FLASH_SR_BSY) + ; FLASH->OPTCR = reg; FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT; __DSB(); - while (FLASH->SR & FLASH_SR_BSY); + while (FLASH->SR & FLASH_SR_BSY) + ; FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK; diff --git a/stm-firmware/stm-periph/rcc-manager.c b/stm-firmware/stm-periph/rcc-manager.c index f98f5cb..2b9a0bd 100644 --- a/stm-firmware/stm-periph/rcc-manager.c +++ b/stm-firmware/stm-periph/rcc-manager.c @@ -95,9 +95,8 @@ int rcc_manager_enable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit int ret_val = 0; struct rcc_enable_count *entry; - if (!rcc_enable_register || bit_no > 31) { + if (!rcc_enable_register || bit_no > 31) return -1000; - } /* Enable the clock in any case, no matter what follows */ *rcc_enable_register |= (1U< 31) { + if (!rcc_enable_register || bit_no > 31) return -1000; - } entry = search_enable_entry_in_list(rcc_enable_register, bit_no); diff --git a/stm-firmware/stm-periph/rng.c b/stm-firmware/stm-periph/rng.c index ceb1ac5..1d8946d 100644 --- a/stm-firmware/stm-periph/rng.c +++ b/stm-firmware/stm-periph/rng.c @@ -30,7 +30,7 @@ void random_number_gen_init(bool int_enable) random_number_gen_reset(int_enable); } -void random_number_gen_deinit() +void random_number_gen_deinit(void) { RNG->CR = 0; __DSB(); @@ -66,5 +66,5 @@ enum random_number_error random_number_gen_get_number(uint32_t *random_number, b *random_number = RNG->DR; /* Return from function with proper status */ - return (value_ready ? RNG_ERROR_OK : RNG_ERROR_NOT_READY); + return value_ready ? RNG_ERROR_OK : RNG_ERROR_NOT_READY; } diff --git a/stm-firmware/stm-periph/spi.c b/stm-firmware/stm-periph/spi.c index 53f0acf..8ab76cf 100644 --- a/stm-firmware/stm-periph/spi.c +++ b/stm-firmware/stm-periph/spi.c @@ -1,22 +1,22 @@ /* 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 . -*/ + * + * 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 @@ -65,7 +65,8 @@ static struct stm_spi_dev *spi_handle_to_struct(stm_spi_handle handle) return dev; } -stm_spi_handle spi_init(struct stm_spi_dev *spi_dev_struct, SPI_TypeDef *spi_regs, const struct stm_spi_settings *settings) +stm_spi_handle spi_init(struct stm_spi_dev *spi_dev_struct, SPI_TypeDef *spi_regs, + const struct stm_spi_settings *settings) { stm_spi_handle ret_handle = NULL; uint32_t reg_val; @@ -131,10 +132,14 @@ void spi_deinit(stm_spi_handle handle) static uint8_t transfer_byte(uint8_t byte, struct stm_spi_dev *dev) { - while (dev->spi_regs->SR & SPI_SR_BSY); + while (dev->spi_regs->SR & SPI_SR_BSY) + ; + dev->spi_regs->DR = (uint16_t)byte; __DSB(); - while((dev->spi_regs->SR & SPI_SR_BSY) || !(dev->spi_regs->SR & SPI_SR_TXE)); + + while ((dev->spi_regs->SR & SPI_SR_BSY) || !(dev->spi_regs->SR & SPI_SR_TXE)) + ; return (uint8_t)dev->spi_regs->DR; } diff --git a/stm-firmware/stm-periph/uart.c b/stm-firmware/stm-periph/uart.c index 27174c5..bfb44ac 100644 --- a/stm-firmware/stm-periph/uart.c +++ b/stm-firmware/stm-periph/uart.c @@ -1,224 +1,227 @@ -/* Reflow Oven Controller - * - * Copyright (C) 2020 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 -#include - -int uart_init(struct stm_uart *uart) -{ - int ret_val = 0; - uint32_t cr3 = 0; - uint32_t cr1 = 0; - - if (!uart) - return -1000; - - rcc_manager_enable_clock(uart->rcc_reg, uart->rcc_bit_no); - - /* Reset all config regs */ - uart->uart_dev->CR1 = uart->uart_dev->CR2 = uart->uart_dev->CR3 = 0UL; - - /* Set baud rate */ - uart->uart_dev->BRR = uart->brr_val; - - /* If DMA buffers are present, configure for DMA use */ - if (uart->dma_rx_buff && uart->rx) { - cr3 |= USART_CR3_DMAR; - - ret_val = dma_ring_buffer_periph_to_mem_initialize(&uart->rx_ring_buff, - uart->base_dma_num, - uart->dma_rx_stream, - uart->rx_buff_count, - 1U, - uart->dma_rx_buff, - (char *)&uart->uart_dev->DR, - uart->dma_rx_trigger_channel); - if (ret_val) - return ret_val; - } - - if (uart->dma_tx_buff && uart->tx) { - ret_val = dma_ring_buffer_mem_to_periph_initialize(&uart->tx_ring_buff, - uart->base_dma_num, - uart->dma_tx_stream, - uart->tx_buff_count, - 1U, - uart->dma_tx_buff, - uart->dma_tx_trigger_channel, - (void *)&uart->uart_dev->DR); - if (ret_val) - return ret_val; - - cr3 |= USART_CR3_DMAT; - } - uart->uart_dev->CR3 = cr3; - - if (uart->tx) - cr1 |= USART_CR1_TE; - if (uart->rx) - cr1 |= USART_CR1_RE; - - /* Enable uart */ - cr1 |= USART_CR1_UE; - uart->uart_dev->CR1 = cr1; - - return 0; -} - -void uart_change_brr(struct stm_uart *uart, uint32_t brr) -{ - if (!uart || !uart->uart_dev) - return; - - uart->brr_val = brr; - uart->uart_dev->BRR = brr; -} - -uint32_t uart_get_brr(struct stm_uart *uart) -{ - if (!uart || !uart->uart_dev) - return 0; - - return uart->brr_val; -} - -void uart_disable(struct stm_uart *uart) -{ - if (!uart) - return; - - uart->uart_dev->CR1 = 0; - uart->uart_dev->CR2 = 0; - uart->uart_dev->CR3 = 0; - - if (uart->rx && uart->dma_rx_buff) - dma_ring_buffer_periph_to_mem_stop(&uart->rx_ring_buff); - - if (uart->dma_tx_buff && uart->tx) - dma_ring_buffer_mem_to_periph_stop(&uart->tx_ring_buff); - - rcc_manager_disable_clock(uart->rcc_reg, uart->rcc_bit_no); -} - -void uart_send_char(struct stm_uart *uart, char c) -{ - if (!uart || !uart->uart_dev) - return; - - while(!(uart->uart_dev->SR & USART_SR_TXE)); - uart->uart_dev->DR = c; -} - -void uart_send_array(struct stm_uart *uart, const char *data, uint32_t len) -{ - uint32_t i; - - for (i = 0; i < len; i++) - uart_send_char(uart, data[i]); -} - -void uart_send_string(struct stm_uart *uart, const char *string) -{ - int i; - - for (i = 0; string[i] != '\0'; i++) - uart_send_char(uart, string[i]); -} - -void uart_send_array_with_dma(struct stm_uart *uart, const char *data, uint32_t len) -{ - if (!uart || !uart->dma_tx_buff) - return; - - dma_ring_buffer_mem_to_periph_insert_data(&uart->tx_ring_buff, data, len); -} - -void uart_send_string_with_dma(struct stm_uart *uart, const char *string) -{ - size_t len; - - len = strlen(string); - uart_send_array_with_dma(uart, string, (uint32_t)len); -} - -int uart_receive_data_with_dma(struct stm_uart *uart, const char **data, size_t *len) -{ - if (!uart) - return -1000; - - return dma_ring_buffer_periph_to_mem_get_data(&uart->rx_ring_buff, (const volatile void **)data, len); -} - -char uart_get_char(struct stm_uart *uart) -{ - if (!uart) - return 0; - /* Wait for data to be available */ - while (!(uart->uart_dev->SR & USART_SR_RXNE)); - - return (char)uart->uart_dev->DR; -} - -int uart_check_rx_avail(struct stm_uart *uart) -{ - if (!uart) - return 0; - - if (uart->uart_dev->SR & USART_SR_RXNE) - return 1; - else - return 0; -} - -void uart_tx_dma_complete_int_callback(struct stm_uart *uart) -{ - if (!uart) - return; - - dma_ring_buffer_mem_to_periph_int_callback(&uart->tx_ring_buff); -} - -size_t uart_dma_tx_queue_avail(struct stm_uart *uart) -{ - size_t fill_level = 0UL; - - if (!uart) - return 0UL; - - (void)dma_ring_buffer_mem_to_periph_fill_level(&uart->tx_ring_buff, &fill_level); - - return fill_level; -} - -size_t uart_dma_rx_queue_avail(struct stm_uart *uart) -{ - size_t fill_level = 0UL; - - if (!uart) - return 0UL; - - (void)dma_ring_buffer_periph_to_mem_fill_level(&uart->rx_ring_buff, &fill_level); - - return fill_level; -} +/* Reflow Oven Controller + * + * Copyright (C) 2020 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 +#include + +int uart_init(struct stm_uart *uart) +{ + int ret_val = 0; + uint32_t cr3 = 0; + uint32_t cr1 = 0; + + if (!uart) + return -1000; + + rcc_manager_enable_clock(uart->rcc_reg, uart->rcc_bit_no); + + /* Reset all config regs */ + uart->uart_dev->CR1 = uart->uart_dev->CR2 = uart->uart_dev->CR3 = 0UL; + + /* Set baud rate */ + uart->uart_dev->BRR = uart->brr_val; + + /* If DMA buffers are present, configure for DMA use */ + if (uart->dma_rx_buff && uart->rx) { + cr3 |= USART_CR3_DMAR; + + ret_val = dma_ring_buffer_periph_to_mem_initialize(&uart->rx_ring_buff, + uart->base_dma_num, + uart->dma_rx_stream, + uart->rx_buff_count, + 1U, + uart->dma_rx_buff, + (char *)&uart->uart_dev->DR, + uart->dma_rx_trigger_channel); + if (ret_val) + return ret_val; + } + + if (uart->dma_tx_buff && uart->tx) { + ret_val = dma_ring_buffer_mem_to_periph_initialize(&uart->tx_ring_buff, + uart->base_dma_num, + uart->dma_tx_stream, + uart->tx_buff_count, + 1U, + uart->dma_tx_buff, + uart->dma_tx_trigger_channel, + (void *)&uart->uart_dev->DR); + if (ret_val) + return ret_val; + + cr3 |= USART_CR3_DMAT; + } + uart->uart_dev->CR3 = cr3; + + if (uart->tx) + cr1 |= USART_CR1_TE; + if (uart->rx) + cr1 |= USART_CR1_RE; + + /* Enable uart */ + cr1 |= USART_CR1_UE; + uart->uart_dev->CR1 = cr1; + + return 0; +} + +void uart_change_brr(struct stm_uart *uart, uint32_t brr) +{ + if (!uart || !uart->uart_dev) + return; + + uart->brr_val = brr; + uart->uart_dev->BRR = brr; +} + +uint32_t uart_get_brr(struct stm_uart *uart) +{ + if (!uart || !uart->uart_dev) + return 0; + + return uart->brr_val; +} + +void uart_disable(struct stm_uart *uart) +{ + if (!uart) + return; + + uart->uart_dev->CR1 = 0; + uart->uart_dev->CR2 = 0; + uart->uart_dev->CR3 = 0; + + if (uart->rx && uart->dma_rx_buff) + dma_ring_buffer_periph_to_mem_stop(&uart->rx_ring_buff); + + if (uart->dma_tx_buff && uart->tx) + dma_ring_buffer_mem_to_periph_stop(&uart->tx_ring_buff); + + rcc_manager_disable_clock(uart->rcc_reg, uart->rcc_bit_no); +} + +void uart_send_char(struct stm_uart *uart, char c) +{ + if (!uart || !uart->uart_dev) + return; + + while (!(uart->uart_dev->SR & USART_SR_TXE)) + ; + + uart->uart_dev->DR = c; +} + +void uart_send_array(struct stm_uart *uart, const char *data, uint32_t len) +{ + uint32_t i; + + for (i = 0; i < len; i++) + uart_send_char(uart, data[i]); +} + +void uart_send_string(struct stm_uart *uart, const char *string) +{ + int i; + + for (i = 0; string[i] != '\0'; i++) + uart_send_char(uart, string[i]); +} + +void uart_send_array_with_dma(struct stm_uart *uart, const char *data, uint32_t len) +{ + if (!uart || !uart->dma_tx_buff) + return; + + dma_ring_buffer_mem_to_periph_insert_data(&uart->tx_ring_buff, data, len); +} + +void uart_send_string_with_dma(struct stm_uart *uart, const char *string) +{ + size_t len; + + len = strlen(string); + uart_send_array_with_dma(uart, string, (uint32_t)len); +} + +int uart_receive_data_with_dma(struct stm_uart *uart, const char **data, size_t *len) +{ + if (!uart) + return -1000; + + return dma_ring_buffer_periph_to_mem_get_data(&uart->rx_ring_buff, (const volatile void **)data, len); +} + +char uart_get_char(struct stm_uart *uart) +{ + if (!uart) + return 0; + /* Wait for data to be available */ + while (!(uart->uart_dev->SR & USART_SR_RXNE)) + ; + + return (char)uart->uart_dev->DR; +} + +int uart_check_rx_avail(struct stm_uart *uart) +{ + if (!uart) + return 0; + + if (uart->uart_dev->SR & USART_SR_RXNE) + return 1; + else + return 0; +} + +void uart_tx_dma_complete_int_callback(struct stm_uart *uart) +{ + if (!uart) + return; + + dma_ring_buffer_mem_to_periph_int_callback(&uart->tx_ring_buff); +} + +size_t uart_dma_tx_queue_avail(struct stm_uart *uart) +{ + size_t fill_level = 0UL; + + if (!uart) + return 0UL; + + (void)dma_ring_buffer_mem_to_periph_fill_level(&uart->tx_ring_buff, &fill_level); + + return fill_level; +} + +size_t uart_dma_rx_queue_avail(struct stm_uart *uart) +{ + size_t fill_level = 0UL; + + if (!uart) + return 0UL; + + (void)dma_ring_buffer_periph_to_mem_fill_level(&uart->rx_ring_buff, &fill_level); + + return fill_level; +} diff --git a/stm-firmware/stm-periph/unique-id.c b/stm-firmware/stm-periph/unique-id.c index aa56130..a80eab5 100644 --- a/stm-firmware/stm-periph/unique-id.c +++ b/stm-firmware/stm-periph/unique-id.c @@ -43,3 +43,23 @@ void stm_dev_rev_id_get(uint32_t *device_id, uint32_t *revision_id) if (revision_id) *revision_id = (DBGMCU->IDCODE & DBGMCU_IDCODE_REV_ID) >> 16; } + +void stm_cpuid_get(uint8_t *implementer, uint8_t *variant, uint16_t *part_no, uint8_t *rev) +{ + uint32_t cpuid; + + cpuid = SCB->CPUID; + + if (implementer) + *implementer = (uint8_t)((cpuid >> 24) & 0xFFU); + + if (variant) + *variant = (uint8_t)((cpuid >> 20) & 0x0FU); + + if (part_no) + *part_no = (uint16_t)((cpuid >> 4) & 0x0FFFU); + + if (rev) + *rev = (uint8_t)(cpuid & 0x0FU); + +} diff --git a/stm-firmware/ui/gui.c b/stm-firmware/ui/gui.c index df65ba9..670d363 100644 --- a/stm-firmware/ui/gui.c +++ b/stm-firmware/ui/gui.c @@ -18,10 +18,12 @@ * If not, see . */ +#include "reflow-controller/version.h" #include #include #include #include +#include #include #include #include @@ -166,9 +168,9 @@ static void gui_menu_about(struct lcd_menu *menu, enum menu_entry_func_entry ent break; last_page = 1; menu_lcd_output(menu, 0, "Version Number:"); - menu_lcd_outputf(menu, 1, "%.*s", LCD_CHAR_WIDTH, xstr(GIT_VER)); - if (strlen(xstr(GIT_VER)) > LCD_CHAR_WIDTH) { - menu_lcd_outputf(menu, 2, "%s", &xstr(GIT_VER)[LCD_CHAR_WIDTH]); + menu_lcd_outputf(menu, 1, "%.*s", LCD_CHAR_WIDTH, version_git_version_string); + if (strlen(version_git_version_string) > LCD_CHAR_WIDTH) { + menu_lcd_outputf(menu, 2, "%s", &version_git_version_string[LCD_CHAR_WIDTH]); } #ifdef DEBUGBUILD menu_lcd_output(menu, 3, "Page 2/5 [DEBUG]"); @@ -691,6 +693,37 @@ static void gui_update_firmware(struct lcd_menu *menu, enum menu_entry_func_entr } } +static void gui_connector_info(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent) +{ + static void *my_parent; + enum button_state button; + + if (entry_type == MENU_ENTRY_FIRST_ENTER) { + my_parent = parent; + menu_display_clear(menu); + + menu_lcd_output(menu, 0, "2,4: DIGIO[0,1]"); + menu_lcd_output(menu, 1, "6: DIGIO2 (TX)"); + menu_lcd_output(menu, 2, "8: DIGIO3 (RX)"); + menu_lcd_output(menu, 3, "10:3V3 Rest:GND"); + } + + if (menu_get_button_ready_state(menu)) { + /* Buttons are ready. Read button */ + button = menu_get_button_state(menu); + /* Throw away any rotation */ + (void)menu_get_rotary_delta(menu); + + if (button == BUTTON_SHORT_RELEASED || button == BUTTON_LONG || + button == BUTTON_LONG_RELEASED) { + /* Exit menu */ + menu_entry_dropback(menu, my_parent); + } + } + + +} + static char *overlay_heading = NULL; static char *overlay_text = NULL; @@ -740,6 +773,7 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr "Error Flags", "About", "Update", + "Connector Info", NULL }; static const menu_func_t root_entry_funcs[] = { @@ -749,6 +783,7 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr gui_menu_err_flags, gui_menu_about, gui_update_firmware, + gui_connector_info, }; enum button_state push_button; int16_t rot_delta; @@ -756,7 +791,6 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr if (entry_type != MENU_ENTRY_CONTINUE) { menu_changed = true; menu_display_clear(menu); - update_display_buffer(0, "Main Menu"); menu_ack_rotary_delta(menu); if (entry_type == MENU_ENTRY_FIRST_ENTER) { list.entry_names = root_entry_names; @@ -767,6 +801,8 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr } } + update_display_buffer(0, sd_card_is_mounted() ? "Main Menu [SD]" : "Main Menu [--]"); + push_button = menu_get_button_state(menu); rot_delta = menu_get_rotary_delta(menu); diff --git a/stm-firmware/ui/shell.c b/stm-firmware/ui/shell.c index 0777e48..68fd94d 100644 --- a/stm-firmware/ui/shell.c +++ b/stm-firmware/ui/shell.c @@ -48,13 +48,11 @@ #include #include #include +#include +#include #include -#ifndef GIT_VER -#define GIT_VER "VERSION NOT SET" -#endif - static shellmatta_instance_t shell; static char shell_buffer[512]; static char IN_SECTION(.ccm.bss) history_buffer[512]; @@ -70,14 +68,19 @@ static shellmatta_retCode_t shell_cmd_ver(const shellmatta_handle_t handle, uint32_t high_id; uint32_t stm_rev_id; uint32_t stm_dev_id; + uint8_t core_rev; + uint8_t core_implementer; + uint8_t core_variant; + uint16_t core_part_no; const char *hw_rev_str; enum hw_revision pcb_rev; stm_unique_id_get(&high_id, &mid_id, &low_id); stm_dev_rev_id_get(&stm_dev_id, &stm_rev_id); - shellmatta_printf(handle, "Reflow Oven Controller Firmware " xstr(GIT_VER) "\r\n" - "Compiled: " __DATE__ " at " __TIME__ "\r\n"); + shellmatta_printf(handle, "Reflow Oven Controller Firmware %s\r\n" + "Compiled: %s at %s\r\n", + version_git_version_string, version_compile_date, version_compile_time); shellmatta_printf(handle, "Serial: %08X-%08X-%08X\r\n", high_id, mid_id, low_id); pcb_rev = get_pcb_hardware_version(); @@ -100,6 +103,12 @@ static shellmatta_retCode_t shell_cmd_ver(const shellmatta_handle_t handle, shellmatta_printf(handle, "STM Device ID: 0x%04X\r\n", stm_dev_id); shellmatta_printf(handle, "STM Revision ID: 0x%04X\r\n", stm_rev_id); + stm_cpuid_get(&core_implementer, &core_variant, &core_part_no, &core_rev); + shellmatta_printf(handle, "CPU Implementer: 0x%02X\r\n", (unsigned int)core_implementer); + shellmatta_printf(handle, "CPU Variant: 0x%02X\r\n", (unsigned int)core_variant); + shellmatta_printf(handle, "CPU Part No.: 0x%04X\r\n", (unsigned int)core_part_no); + shellmatta_printf(handle, "CPU Revision: 0x%02X\r\n", (unsigned int)core_rev); + return SHELLMATTA_OK; } @@ -849,6 +858,7 @@ shellmatta_retCode_t shell_cmd_execute(const shellmatta_handle_t handle, const c shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, const char *args, uint32_t len) { uint64_t counter; + uint32_t core_cycle_count; (void)args; (void)len; char option; @@ -856,8 +866,10 @@ shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, con uint32_t arg_len; int opt_stat; bool clear = false; + bool hex = false; const shellmatta_opt_long_t options[] = { {"clear", 'c', SHELLMATTA_OPT_ARG_NONE}, + {"hex", 'h', SHELLMATTA_OPT_ARG_NONE}, {NULL, '\0', SHELLMATTA_OPT_ARG_NONE}, }; @@ -869,6 +881,8 @@ shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, con case 'c': clear = true; break; + case 'h': + hex = true; default: break; } @@ -876,10 +890,18 @@ shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, con counter = main_cycle_counter_get(); - shellmatta_printf(handle, "%"PRIu64"\r\n", counter); - if (clear) - main_cycle_counter_init(); - + core_cycle_count = core_cycle_counter_get(); + if (hex) { + shellmatta_printf(handle, "Main loop: 0x%016"PRIX64"\r\n", counter); + shellmatta_printf(handle, "CPU cycles: 0x%08"PRIX32"\r\n", core_cycle_count); + } else { + shellmatta_printf(handle, "Main loop: %"PRIu64"\r\n", counter); + shellmatta_printf(handle, "CPU cycles: %"PRIu32"\r\n", core_cycle_count); + } + if (clear) { + main_cycle_counter_reset(); + core_cycle_counter_reset(); + } return SHELLMATTA_OK; } @@ -997,6 +1019,53 @@ shellmatta_retCode_t shell_cmd_set_baud(const shellmatta_handle_t handle, const return SHELLMATTA_OK; } +static void shell_print_crc_line(const shellmatta_handle_t handle, const char *name, + uint32_t crc, uint32_t crc_expected) +{ + shellmatta_printf(handle, "%-15s0x%08x 0x%08x [%s]\r\n", + name, + crc, + crc_expected, + crc != crc_expected ? "\e[1;31mERR\e[m" : "\e[32mOK\e[m"); +} + +shellmatta_retCode_t shell_cmd_flash_crc(const shellmatta_handle_t handle, const char *args, uint32_t len) +{ + (void)args; + (void)len; + uint32_t crc = 0; + uint32_t crc_expected = 0; + int res; + + shellmatta_printf(handle, " Calculated Expected State\r\n\r\n"); + + res = flash_crc_calc_section(FLASH_CRC_VECTOR, &crc); + crc_expected = flash_crc_get_expected_crc(FLASH_CRC_VECTOR); + if (res) + shellmatta_printf(handle, "Error during calculation!\r\n"); + shell_print_crc_line(handle, "Vector CRC:", crc, crc_expected); + + res = flash_crc_calc_section(FLASH_CRC_TEXT, &crc); + crc_expected = flash_crc_get_expected_crc(FLASH_CRC_TEXT); + if (res) + shellmatta_printf(handle, "Error during calculation!\r\n"); + shell_print_crc_line(handle, "Code CRC:", crc, crc_expected); + + res = flash_crc_calc_section(FLASH_CRC_DATA, &crc); + crc_expected = flash_crc_get_expected_crc(FLASH_CRC_DATA); + if (res) + shellmatta_printf(handle, "Error during calculation!\r\n"); + shell_print_crc_line(handle, "Data CRC:", crc, crc_expected); + + res = flash_crc_calc_section(FLASH_CRC_CCMDATA, &crc); + crc_expected = flash_crc_get_expected_crc(FLASH_CRC_CCMDATA); + if (res) + shellmatta_printf(handle, "Error during calculation!\r\n"); + shell_print_crc_line(handle, "CCM Data CRC:", crc, crc_expected); + + return SHELLMATTA_OK; +} + //typedef struct shellmatta_cmd //{ // char *cmd; /**< command name */ @@ -1006,7 +1075,7 @@ shellmatta_retCode_t shell_cmd_set_baud(const shellmatta_handle_t handle, const // shellmatta_cmdFct_t cmdFct; /**< pointer to the cmd callack function */ // struct shellmatta_cmd *next; /**< pointer to next command or NULL */ //} shellmatta_cmd_t; -static shellmatta_cmd_t cmd[25] = { +static shellmatta_cmd_t cmd[26] = { { .cmd = "version", .cmdAlias = "ver", @@ -1202,10 +1271,18 @@ static shellmatta_cmd_t cmd[25] = { }, { .cmd = "baudrate", - .cmdAlias = "opt-bytes", + .cmdAlias = "baud", .helpText = "Set a new temporary baudrate for the UART", .usageText = "baudrate ", .cmdFct = shell_cmd_set_baud, + .next = &cmd[25], + }, + { + .cmd = "flashcrc", + .cmdAlias = "fcrc", + .helpText = "Calculate the Flash CRCs", + .usageText = "flashcrc", + .cmdFct = shell_cmd_flash_crc, .next = NULL, }, diff --git a/stm-firmware/updater/ram-code/CMakeLists.txt b/stm-firmware/updater/ram-code/CMakeLists.txt index ddd12a2..dc660a3 100644 --- a/stm-firmware/updater/ram-code/CMakeLists.txt +++ b/stm-firmware/updater/ram-code/CMakeLists.txt @@ -31,7 +31,7 @@ add_executable(${ELFFILE} ${SRCS} ${FATFS_SRCS} ${SDIO_SRCS} ${STM_PERIPH_SRCS} target_include_directories(${ELFFILE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ../../include ${CMAKE_CURRENT_SOURCE_DIR}/3rd-party) 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 -DGIT_VER=${GIT_DESCRIBE} -DHSE_VALUE=8000000UL -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4 -DSAFETY_MEMORY_STRIPOUT_DUMP) +target_compile_definitions(${ELFFILE} PRIVATE -DHSE_VALUE=8000000UL -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4 -DSAFETY_MEMORY_STRIPOUT_DUMP) 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") diff --git a/stm-firmware/updater/ram-code/bin2carray.py b/stm-firmware/updater/ram-code/bin2carray.py index c0f0ca3..124b118 100755 --- a/stm-firmware/updater/ram-code/bin2carray.py +++ b/stm-firmware/updater/ram-code/bin2carray.py @@ -1,35 +1,45 @@ #!env python -# Convert a file to a c array -# bin2carray +""" +Convert a file to a c array +bin2carray +""" import os import os.path import sys -if len(sys.argv) < 3: - sys.exit(-1) +def main(): + """ + Main script function + """ + if len(sys.argv) < 3: + return -1 -source_file = sys.argv[2] -dest_file = sys.argv[1] + source_file = sys.argv[2] + dest_file = sys.argv[1] -print("%s --> %s" % (source_file, dest_file)) + print(f'{source_file} --> {dest_file}') -with open(source_file, "rb") as src: - data = src.read() + with open(source_file, 'rb') as src: + data = src.read() -with open(dest_file, "w") as dest: - header_guard = "__" + os.path.basename(dest_file).replace('.', '_').replace('-', '_') + "_H__" - dest.write("#ifndef %s\n" % (header_guard)) - dest.write("#define %s\n" % (header_guard)) - dest.write("static const char binary_blob[%d] = {\n" % (len(data))) - for current,idx in zip(data, range(len(data))): - if ((idx+1) % 4 == 0): - dest.write(hex(current)+",\n") - else: - dest.write(hex(current)+",") + with open(dest_file, 'w', encoding='utf-8') as dest: + header_guard = '_' + os.path.basename(dest_file).replace('.', '_').replace('-', '_') + '_H_' + header_guard = header_guard.upper() + dest.write(f'#ifndef {header_guard}\n') + dest.write(f'#define {header_guard}\n') + dest.write(f'static const char binary_blob[{len(data)}] = {{\n') + for idx, current in enumerate(data, start=1): + if idx % 4 == 0: + dest.write(hex(current)+',\n') + else: + dest.write(hex(current)+',') - dest.write("};\n") - dest.write("#endif /* %s */\n" % (header_guard)) + dest.write('};\n') + dest.write(f'#endif /* {header_guard} */\n') -sys.exit(0) + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/stm-firmware/updater/ram-code/fatfs/ff.c b/stm-firmware/updater/ram-code/fatfs/ff.c index 4ed9ce2..d60817b 100644 --- a/stm-firmware/updater/ram-code/fatfs/ff.c +++ b/stm-firmware/updater/ram-code/fatfs/ff.c @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem Module R0.14b / +/ FatFs - Generic FAT Filesystem Module R0.15 w/patch1 / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2021, ChaN, all right reserved. +/ Copyright (C) 2022, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -20,8 +20,8 @@ #include -#include /* Declarations of FatFs API */ -#include /* Declarations of device I/O functions */ +#include /* Declarations of FatFs API */ +#include /* Declarations of device I/O functions */ /*-------------------------------------------------------------------------- @@ -30,7 +30,7 @@ ---------------------------------------------------------------------------*/ -#if FF_DEFINED != 86631 /* Revision ID */ +#if FF_DEFINED != 80286 /* Revision ID */ #error Wrong include file (ff.h). #endif @@ -208,26 +208,26 @@ #define PTE_StLba 8 /* MBR PTE: Start in LBA */ #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ -#define GPTH_Sign 0 /* GPT: Header signature (8-byte) */ -#define GPTH_Rev 8 /* GPT: Revision (DWORD) */ -#define GPTH_Size 12 /* GPT: Header size (DWORD) */ -#define GPTH_Bcc 16 /* GPT: Header BCC (DWORD) */ -#define GPTH_CurLba 24 /* GPT: Main header LBA (QWORD) */ -#define GPTH_BakLba 32 /* GPT: Backup header LBA (QWORD) */ -#define GPTH_FstLba 40 /* GPT: First LBA for partitions (QWORD) */ -#define GPTH_LstLba 48 /* GPT: Last LBA for partitions (QWORD) */ -#define GPTH_DskGuid 56 /* GPT: Disk GUID (16-byte) */ -#define GPTH_PtOfs 72 /* GPT: Partation table LBA (QWORD) */ -#define GPTH_PtNum 80 /* GPT: Number of table entries (DWORD) */ -#define GPTH_PteSize 84 /* GPT: Size of table entry (DWORD) */ -#define GPTH_PtBcc 88 /* GPT: Partation table BCC (DWORD) */ -#define SZ_GPTE 128 /* GPT: Size of partition table entry */ +#define GPTH_Sign 0 /* GPT HDR: Signature (8-byte) */ +#define GPTH_Rev 8 /* GPT HDR: Revision (DWORD) */ +#define GPTH_Size 12 /* GPT HDR: Header size (DWORD) */ +#define GPTH_Bcc 16 /* GPT HDR: Header BCC (DWORD) */ +#define GPTH_CurLba 24 /* GPT HDR: This header LBA (QWORD) */ +#define GPTH_BakLba 32 /* GPT HDR: Another header LBA (QWORD) */ +#define GPTH_FstLba 40 /* GPT HDR: First LBA for partition data (QWORD) */ +#define GPTH_LstLba 48 /* GPT HDR: Last LBA for partition data (QWORD) */ +#define GPTH_DskGuid 56 /* GPT HDR: Disk GUID (16-byte) */ +#define GPTH_PtOfs 72 /* GPT HDR: Partition table LBA (QWORD) */ +#define GPTH_PtNum 80 /* GPT HDR: Number of table entries (DWORD) */ +#define GPTH_PteSize 84 /* GPT HDR: Size of table entry (DWORD) */ +#define GPTH_PtBcc 88 /* GPT HDR: Partition table BCC (DWORD) */ +#define SZ_GPTE 128 /* GPT PTE: Size of partition table entry */ #define GPTE_PtGuid 0 /* GPT PTE: Partition type GUID (16-byte) */ #define GPTE_UpGuid 16 /* GPT PTE: Partition unique GUID (16-byte) */ -#define GPTE_FstLba 32 /* GPT PTE: First LBA (QWORD) */ -#define GPTE_LstLba 40 /* GPT PTE: Last LBA inclusive (QWORD) */ -#define GPTE_Flags 48 /* GPT PTE: Flags (QWORD) */ -#define GPTE_Name 56 /* GPT PTE: Name */ +#define GPTE_FstLba 32 /* GPT PTE: First LBA of partition (QWORD) */ +#define GPTE_LstLba 40 /* GPT PTE: Last LBA of partition (QWORD) */ +#define GPTE_Flags 48 /* GPT PTE: Partition flags (QWORD) */ +#define GPTE_Name 56 /* GPT PTE: Partition name */ /* Post process on fatal error in the file operations */ @@ -239,7 +239,7 @@ #if FF_USE_LFN == 1 #error Static LFN work area cannot be used in thread-safe configuration #endif -#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#define LEAVE_FF(fs, res) { unlock_volume(fs, res); return res; } #else #define LEAVE_FF(fs, res) return res #endif @@ -278,15 +278,15 @@ /* File lock controls */ -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK #if FF_FS_READONLY #error FF_FS_LOCK must be 0 at read-only configuration #endif typedef struct { - FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ + FATFS* fs; /* Object ID 1, volume (NULL:blank entry) */ DWORD clu; /* Object ID 2, containing directory (0:root) */ DWORD ofs; /* Object ID 3, offset in the directory */ - WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ + UINT ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ } FILESEM; #endif @@ -461,20 +461,23 @@ typedef struct { #if FF_VOLUMES < 1 || FF_VOLUMES > 10 #error Wrong FF_VOLUMES setting #endif -static FATFS* FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ +static FATFS *FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ static WORD Fsid; /* Filesystem mount ID */ #if FF_FS_RPATH != 0 -static BYTE CurrVol; /* Current drive */ +static BYTE CurrVol; /* Current drive set by f_chdrive() */ #endif #if FF_FS_LOCK != 0 static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ +#if FF_FS_REENTRANT +static BYTE SysLock; /* System lock flag (0:no mutex, 1:unlocked, 2:locked) */ +#endif #endif #if FF_STR_VOLUME_ID #ifdef FF_VOLUME_STRS -static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ +static const char *const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ #endif #endif @@ -563,7 +566,8 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #if FF_CODE_PAGE == 0 /* Run-time code page configuration */ #define CODEPAGE CodePage static WORD CodePage; /* Current code page */ -static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ +static const BYTE* ExCvt; /* Ptr to SBCS up-case table Ct???[] (null:not used) */ +static const BYTE* DbcTbl; /* Ptr to DBCS code range table Dc???[] (null:not used) */ static const BYTE Ct437[] = TBL_CT437; static const BYTE Ct720[] = TBL_CT720; @@ -887,21 +891,45 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ -static int lock_fs ( /* 1:Ok, 0:timeout */ - FATFS* fs /* Filesystem object */ + +static int lock_volume ( /* 1:Ok, 0:timeout */ + FATFS* fs, /* Filesystem object to lock */ + int syslock /* System lock required */ ) { - return ff_req_grant(fs->sobj); + int rv; + + +#if FF_FS_LOCK + rv = ff_mutex_take(fs->ldrv); /* Lock the volume */ + if (rv && syslock) { /* System lock reqiered? */ + rv = ff_mutex_take(FF_VOLUMES); /* Lock the system */ + if (rv) { + SysLock = 2; /* System lock succeeded */ + } else { + ff_mutex_give(fs->ldrv); /* Failed system lock */ + } + } +#else + rv = syslock ? ff_mutex_take(fs->ldrv) : ff_mutex_take(fs->ldrv); /* Lock the volume (this is to prevent compiler warning) */ +#endif + return rv; } -static void unlock_fs ( +static void unlock_volume ( FATFS* fs, /* Filesystem object */ FRESULT res /* Result code to be returned */ ) { if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { - ff_rel_grant(fs->sobj); +#if FF_FS_LOCK + if (SysLock == 2) { /* Is the system locked? */ + SysLock = 1; + ff_mutex_give(FF_VOLUMES); + } +#endif + ff_mutex_give(fs->ldrv); /* Unlock the volume */ } } @@ -909,12 +937,12 @@ static void unlock_fs ( -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK /*-----------------------------------------------------------------------*/ -/* File lock control functions */ +/* File shareing control functions */ /*-----------------------------------------------------------------------*/ -static FRESULT chk_lock ( /* Check if the file can be accessed */ +static FRESULT chk_share ( /* Check if the file can be accessed */ DIR* dp, /* Directory object pointing the file to be checked */ int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ ) @@ -941,16 +969,16 @@ static FRESULT chk_lock ( /* Check if the file can be accessed */ } -static int enq_lock (void) /* Check if an entry is available for a new object */ +static int enq_share (void) /* Check if an entry is available for a new object */ { UINT i; - for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; /* Find a free entry */ return (i == FF_FS_LOCK) ? 0 : 1; } -static UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ +static UINT inc_share ( /* Increment object open counter and returns its index (0:Internal error) */ DIR* dp, /* Directory object pointing the file to register or increment */ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ ) @@ -965,7 +993,7 @@ static UINT inc_lock ( /* Increment object open counter and returns its index (0 } if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ - for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; /* Find a free entry */ if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ Files[i].fs = dp->obj.fs; Files[i].clu = dp->obj.sclust; @@ -981,30 +1009,32 @@ static UINT inc_lock ( /* Increment object open counter and returns its index (0 } -static FRESULT dec_lock ( /* Decrement object open counter */ +static FRESULT dec_share ( /* Decrement object open counter */ UINT i /* Semaphore index (1..) */ ) { - WORD n; + UINT n; FRESULT res; if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ n = Files[i].ctr; - if (n == 0x100) n = 0; /* If write mode open, delete the entry */ + if (n == 0x100) n = 0; /* If write mode open, delete the object semaphore */ if (n > 0) n--; /* Decrement read mode open count */ Files[i].ctr = n; - if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ + if (n == 0) { /* Delete the object semaphore if open count becomes zero */ + Files[i].fs = 0; /* Free the entry << 1, there is a potential error in this process >>> */ + } res = FR_OK; } else { - res = FR_INT_ERR; /* Invalid index nunber */ + res = FR_INT_ERR; /* Invalid index number */ } return res; } -static void clear_lock ( /* Clear lock entries of the volume */ - FATFS *fs +static void clear_share ( /* Clear all lock entries of the volume */ + FATFS* fs ) { UINT i; @@ -1014,7 +1044,7 @@ static void clear_lock ( /* Clear lock entries of the volume */ } } -#endif /* FF_FS_LOCK != 0 */ +#endif /* FF_FS_LOCK */ @@ -1599,7 +1629,8 @@ static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FSIZE_t ofs /* File offset to be converted to cluster# */ ) { - DWORD cl, ncl, *tbl; + DWORD cl, ncl; + DWORD *tbl; FATFS *fs = fp->obj.fs; @@ -1990,7 +2021,7 @@ static void gen_numname ( seq = (UINT)sreg; } - /* Make suffix (~ + hexdecimal) */ + /* Make suffix (~ + hexadecimal) */ i = 7; do { c = (BYTE)((seq % 16) + '0'); seq /= 16; @@ -2092,17 +2123,17 @@ static DWORD xsum32 ( /* Returns 32-bit checksum */ -/*-----------------------------------*/ -/* exFAT: Get a directry entry block */ -/*-----------------------------------*/ +/*------------------------------------*/ +/* exFAT: Get a directory entry block */ +/*------------------------------------*/ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ - DIR* dp /* Reading direcotry object pointing top of the entry block to load */ + DIR* dp /* Reading directory object pointing top of the entry block to load */ ) { FRESULT res; UINT i, sz_ent; - BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory directory entry block 85+C0+C1s */ /* Load file directory entry */ @@ -2166,7 +2197,7 @@ static void init_alloc_info ( /*------------------------------------------------*/ static FRESULT load_obj_xdir ( - DIR* dp, /* Blank directory object to be used to access containing direcotry */ + DIR* dp, /* Blank directory object to be used to access containing directory */ const FFOBJID* obj /* Object with its containing directory information */ ) { @@ -2195,18 +2226,18 @@ static FRESULT load_obj_xdir ( /*----------------------------------------*/ static FRESULT store_xdir ( - DIR* dp /* Pointer to the direcotry object */ + DIR* dp /* Pointer to the directory object */ ) { FRESULT res; UINT nent; - BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the directory entry block 85+C0+C1s */ /* Create set sum */ st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); nent = dirb[XDIR_NumSec] + 1; - /* Store the direcotry entry block to the directory */ + /* Store the directory entry block to the directory */ res = dir_sdi(dp, dp->blk_ofs); while (res == FR_OK) { res = move_window(dp->obj.fs, dp->sect); @@ -2223,11 +2254,11 @@ static FRESULT store_xdir ( /*-------------------------------------------*/ -/* exFAT: Create a new directory enrty block */ +/* exFAT: Create a new directory entry block */ /*-------------------------------------------*/ static void create_xdir ( - BYTE* dirb, /* Pointer to the direcotry entry block buffer */ + BYTE* dirb, /* Pointer to the directory entry block buffer */ const WCHAR* lfn /* Pointer to the object name */ ) { @@ -2610,19 +2641,23 @@ static void get_fileinfo ( si = SZDIRE * 2; di = 0; /* 1st C1 entry in the entry block */ hs = 0; while (nc < fs->dirbuf[XDIR_NumName]) { - if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + if (si >= MAXDIRB(FF_MAX_LFN)) { /* Truncated directory block? */ + di = 0; break; + } + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ wc = ld_word(fs->dirbuf + si); si += 2; nc++; /* Get a character */ - if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ - hs = wc; continue; /* Get low surrogate */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ } nw = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Buffer overflow or wrong char? */ + if (nw == 0) { /* Buffer overflow or wrong char? */ + di = 0; break; + } di += nw; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ - if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ + if (di == 0) fno->fname[di++] = '\?'; /* Inaccessible object name? */ fno->fname[di] = 0; /* Terminate the name */ fno->altname[0] = 0; /* exFAT does not support SFN */ @@ -2643,7 +2678,9 @@ static void get_fileinfo ( hs = wc; continue; /* Get low surrogate */ } nw = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Buffer overflow or wrong char? */ + if (nw == 0) { /* Buffer overflow or wrong char? */ + di = 0; break; + } di += nw; hs = 0; } @@ -2663,9 +2700,13 @@ static void get_fileinfo ( wc = wc << 8 | dp->dir[si++]; } wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ - if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ + if (wc == 0) { /* Wrong char in the current code page? */ + di = 0; break; + } nw = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Buffer overflow? */ + if (nw == 0) { /* Buffer overflow? */ + di = 0; break; + } di += nw; #else /* ANSI/OEM output */ fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ @@ -2674,8 +2715,8 @@ static void get_fileinfo ( fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ - if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ - fno->fname[di++] = '?'; + if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccessible */ + fno->fname[di++] = '\?'; } else { for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ wc = (WCHAR)fno->altname[si]; @@ -2756,7 +2797,8 @@ static int pattern_match ( /* 0:mismatched, 1:matched */ UINT recur /* Recursion count */ ) { - const TCHAR *pptr, *nptr; + const TCHAR *pptr; + const TCHAR *nptr; DWORD pchr, nchr; UINT sk; @@ -2770,12 +2812,16 @@ static int pattern_match ( /* 0:mismatched, 1:matched */ do { pptr = pat; nptr = nam; /* Top of pattern and name to match */ for (;;) { - if (*pptr == '?' || *pptr == '*') { /* Wildcard term? */ + if (*pptr == '\?' || *pptr == '*') { /* Wildcard term? */ if (recur == 0) return 0; /* Too many wildcard terms? */ sk = 0; do { /* Analyze the wildcard term */ - if (*pptr++ == '?') sk++; else sk |= 0x100; - } while (*pptr == '?' || *pptr == '*'); + if (*pptr++ == '\?') { + sk++; + } else { + sk |= 0x100; + } + } while (*pptr == '\?' || *pptr == '*'); if (pattern_match(pptr, nptr, sk, recur - 1)) return 1; /* Test new branch (recursive call) */ nchr = *nptr; break; /* Branch mismatched */ } @@ -2805,10 +2851,11 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr { #if FF_USE_LFN /* LFN configuration */ BYTE b, cf; - WCHAR wc, *lfn; + WCHAR wc; + WCHAR *lfn; + const TCHAR* p; DWORD uc; UINT i, ni, si, di; - const TCHAR *p; /* Create LFN into LFN working buffer */ @@ -2930,7 +2977,8 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr #else /* FF_USE_LFN : Non-LFN configuration */ - BYTE c, d, *sfn; + BYTE c, d; + BYTE *sfn; UINT ni, si, i; const char *p; @@ -3091,7 +3139,8 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb const TCHAR** path /* Pointer to pointer to the path name */ ) { - const TCHAR *tp, *tt; + const TCHAR *tp; + const TCHAR *tt; TCHAR tc; int i; int vol = -1; @@ -3102,7 +3151,9 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb tt = tp = *path; if (!tp) return vol; /* Invalid path name? */ - do tc = *tt++; while (!IsTerminator(tc) && tc != ':'); /* Find a colon in the path */ + do { /* Find a colon in the path */ + tc = *tt++; + } while (!IsTerminator(tc) && tc != ':'); if (tc == ':') { /* DOS/Windows style volume ID? */ i = FF_VOLUMES; @@ -3190,16 +3241,18 @@ static int test_gpt_header ( /* 0:Invalid, 1:Valid */ ) { UINT i; - DWORD bcc; + DWORD bcc, hlen; - if (memcmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16)) return 0; /* Check sign, version (1.0) and length (92) */ - for (i = 0, bcc = 0xFFFFFFFF; i < 92; i++) { /* Check header BCC */ + if (memcmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1", 12)) return 0; /* Check signature and version (1.0) */ + hlen = ld_dword(gpth + GPTH_Size); /* Check header size */ + if (hlen < 92 || hlen > FF_MIN_SS) return 0; + for (i = 0, bcc = 0xFFFFFFFF; i < hlen; i++) { /* Check header BCC */ bcc = crc32(bcc, i - GPTH_Bcc < 4 ? 0 : gpth[i]); } if (~bcc != ld_dword(gpth + GPTH_Bcc)) return 0; if (ld_dword(gpth + GPTH_PteSize) != SZ_GPTE) return 0; /* Table entry size (must be SZ_GPTE bytes) */ - if (ld_dword(gpth + GPTH_PtNum) > 128) return 0; /* Table size (must be 128 entries or less) */ + if (ld_dword(gpth + GPTH_PtNum) > 128) return 0; /* Table size (must be 128 entries or less) */ return 1; } @@ -3209,7 +3262,7 @@ static int test_gpt_header ( /* 0:Invalid, 1:Valid */ /* Generate random value */ static DWORD make_rand ( DWORD seed, /* Seed value */ - BYTE* buff, /* Output buffer */ + BYTE *buff, /* Output buffer */ UINT n /* Data length */ ) { @@ -3277,7 +3330,7 @@ static UINT check_fs ( /* 0:FAT/FAT32 VBR, 1:exFAT VBR, 2:Not FAT and valid BS, static UINT find_volume ( /* Returns BS status found in the hosting drive */ FATFS* fs, /* Filesystem object */ - UINT part /* Partition to fined = 0:auto, 1..:forced */ + UINT part /* Partition to fined = 0:find as SFD and partitions, >0:forced partition number */ ) { UINT fmt, i; @@ -3332,15 +3385,15 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ FATFS** rfs, /* Pointer to pointer to the found filesystem object */ - BYTE mode /* !=0: Check write protection for write access */ + BYTE mode /* Desiered access mode to check write protection */ ) { int vol; + FATFS *fs; DSTATUS stat; LBA_t bsect; DWORD tsect, sysect, fasize, nclst, szbfat; WORD nrsv; - FATFS *fs; UINT fmt; @@ -3353,7 +3406,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs = FatFs[vol]; /* Get pointer to the filesystem object */ if (!fs) return FR_NOT_ENABLED; /* Is the filesystem object available? */ #if FF_FS_REENTRANT - if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ + if (!lock_volume(fs, 1)) return FR_TIMEOUT; /* Lock the volume, and system if needed */ #endif *rfs = fs; /* Return pointer to the filesystem object */ @@ -3371,9 +3424,8 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ /* The filesystem object is not valid. */ /* Following code attempts to mount the volume. (find an FAT volume, analyze the BPB and initialize the filesystem object) */ - fs->fs_type = 0; /* Clear the filesystem object */ - fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ - stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ + fs->fs_type = 0; /* Invalidate the filesystem object */ + stat = disk_initialize(fs->pdrv); /* Initialize the volume hosting physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ } @@ -3385,11 +3437,11 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif - /* Find an FAT volume on the drive */ + /* Find an FAT volume on the hosting drive */ fmt = find_volume(fs, LD2PT(vol)); - if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ + if (fmt == 4) return FR_DISK_ERR; /* An error occurred in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ - bsect = fs->winsect; /* Volume offset */ + bsect = fs->winsect; /* Volume offset in the hosting physical drive */ /* An FAT volume is found (bsect). Following code initializes the filesystem object */ @@ -3426,7 +3478,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->volbase = bsect; fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); - if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ + if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */ fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); /* Get bitmap location and check if it is contiguous (implementation assumption) */ @@ -3447,7 +3499,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); if (cv == 0xFFFFFFFF) break; /* Last link? */ - if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented? */ + if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented bitmap? */ } #if !FF_FS_READONLY @@ -3534,7 +3586,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #endif /* !FF_FS_READONLY */ } - fs->fs_type = (BYTE)fmt;/* FAT sub-type */ + fs->fs_type = (BYTE)fmt;/* FAT sub-type (the filesystem object gets valid) */ fs->id = ++Fsid; /* Volume mount ID */ #if FF_USE_LFN == 1 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ @@ -3545,8 +3597,8 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #if FF_FS_RPATH != 0 fs->cdir = 0; /* Initialize current directory */ #endif -#if FF_FS_LOCK != 0 /* Clear file lock semaphores */ - clear_lock(fs); +#if FF_FS_LOCK /* Clear file lock semaphores */ + clear_share(fs); #endif return FR_OK; } @@ -3559,7 +3611,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ /*-----------------------------------------------------------------------*/ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ - FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */ + FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR structure, to check validity */ FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ ) { @@ -3568,22 +3620,22 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ #if FF_FS_REENTRANT - if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ - if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + if (lock_volume(obj->fs, 0)) { /* Take a grant to access the volume */ + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting phsical drive is kept initialized */ res = FR_OK; } else { - unlock_fs(obj->fs, FR_OK); + unlock_volume(obj->fs, FR_OK); /* Invalidated volume, abort to access */ } - } else { + } else { /* Could not take */ res = FR_TIMEOUT; } #else - if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting phsical drive is kept initialized */ res = FR_OK; } #endif } - *rfs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ + *rfs = (res == FR_OK) ? obj->fs : 0; /* Return corresponding filesystem object if it is valid */ return res; } @@ -3614,30 +3666,42 @@ FRESULT f_mount ( const TCHAR *rp = path; - /* Get logical drive number */ + /* Get volume ID (logical drive number) */ vol = get_ldnumber(&rp); if (vol < 0) return FR_INVALID_DRIVE; - cfs = FatFs[vol]; /* Pointer to fs object */ + cfs = FatFs[vol]; /* Pointer to the filesystem object of the volume */ - if (cfs) { -#if FF_FS_LOCK != 0 - clear_lock(cfs); + if (cfs) { /* Unregister current filesystem object if regsitered */ + FatFs[vol] = 0; +#if FF_FS_LOCK + clear_share(cfs); #endif -#if FF_FS_REENTRANT /* Discard sync object of the current volume */ - if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; +#if FF_FS_REENTRANT /* Discard mutex of the current volume */ + ff_mutex_delete(vol); #endif - cfs->fs_type = 0; /* Clear old fs object */ + cfs->fs_type = 0; /* Invalidate the filesystem object to be unregistered */ } - if (fs) { - fs->fs_type = 0; /* Clear new fs object */ -#if FF_FS_REENTRANT /* Create sync object for the new volume */ - if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; + if (fs) { /* Register new filesystem object */ + fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ +#if FF_FS_REENTRANT /* Create a volume mutex */ + fs->ldrv = (BYTE)vol; /* Owner volume ID */ + if (!ff_mutex_create(vol)) return FR_INT_ERR; +#if FF_FS_LOCK + if (SysLock == 0) { /* Create a system mutex if needed */ + if (!ff_mutex_create(FF_VOLUMES)) { + ff_mutex_delete(vol); + return FR_INT_ERR; + } + SysLock = 1; /* System mutex is ready */ + } #endif +#endif + fs->fs_type = 0; /* Invalidate the new filesystem object */ + FatFs[vol] = fs; /* Register new fs object */ } - FatFs[vol] = fs; /* Register new fs object */ - if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ + if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted in subsequent file functions */ res = mount_volume(&path, &fs, 0); /* Force mounted the volume */ LEAVE_FF(fs, res); @@ -3681,9 +3745,9 @@ FRESULT f_open ( if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; } -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK else { - res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ + res = chk_share(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ } #endif } @@ -3691,8 +3755,8 @@ FRESULT f_open ( if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ -#if FF_FS_LOCK != 0 - res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; +#if FF_FS_LOCK + res = enq_share() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif @@ -3761,8 +3825,8 @@ FRESULT f_open ( if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dj.dir; -#if FF_FS_LOCK != 0 - fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ +#if FF_FS_LOCK + fp->obj.lockid = inc_share(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ if (fp->obj.lockid == 0) res = FR_INT_ERR; #endif } @@ -3825,8 +3889,8 @@ FRESULT f_open ( #endif } } -#if FF_FS_LOCK != 0 - if (res != FR_OK) dec_lock(fp->obj.lockid); /* Decrement file open counter if seek failed */ +#if FF_FS_LOCK + if (res != FR_OK) dec_share(fp->obj.lockid); /* Decrement file open counter if seek failed */ #endif } #endif @@ -3921,7 +3985,7 @@ FRESULT f_read ( fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ } #endif fp->sect = sect; @@ -4163,14 +4227,14 @@ FRESULT f_close ( { res = validate(&fp->obj, &fs); /* Lock volume */ if (res == FR_OK) { -#if FF_FS_LOCK != 0 - res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ +#if FF_FS_LOCK + res = dec_share(fp->obj.lockid); /* Decrement file open counter */ if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ #else fp->obj.fs = 0; /* Invalidate file object */ #endif #if FF_FS_REENTRANT - unlock_fs(fs, FR_OK); /* Unlock volume */ + unlock_volume(fs, FR_OK); /* Unlock volume */ #endif } } @@ -4344,7 +4408,9 @@ FRESULT f_getcwd ( #endif /* Add current directory path */ if (res == FR_OK) { - do *tp++ = buff[i++]; while (i < len); /* Copy stacked path string */ + do { /* Copy stacked path string */ + *tp++ = buff[i++]; + } while (i < len); } } FREE_NAMBUF(); @@ -4551,7 +4617,7 @@ FRESULT f_opendir ( if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ + dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; dp->obj.c_ofs = dp->blk_ofs; init_alloc_info(fs, &dp->obj); /* Get object allocation info */ @@ -4567,10 +4633,10 @@ FRESULT f_opendir ( if (res == FR_OK) { dp->obj.id = fs->id; res = dir_sdi(dp, 0); /* Rewind directory */ -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK if (res == FR_OK) { if (dp->obj.sclust != 0) { - dp->obj.lockid = inc_lock(dp, 0); /* Lock the sub directory */ + dp->obj.lockid = inc_share(dp, 0); /* Lock the sub directory */ if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; } else { dp->obj.lockid = 0; /* Root directory need not to be locked */ @@ -4582,7 +4648,7 @@ FRESULT f_opendir ( FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } - if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function faild */ + if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function failed */ LEAVE_FF(fs, res); } @@ -4604,14 +4670,14 @@ FRESULT f_closedir ( res = validate(&dp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { -#if FF_FS_LOCK != 0 - if (dp->obj.lockid) res = dec_lock(dp->obj.lockid); /* Decrement sub-directory open counter */ +#if FF_FS_LOCK + if (dp->obj.lockid) res = dec_share(dp->obj.lockid); /* Decrement sub-directory open counter */ if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ #else dp->obj.fs = 0; /* Invalidate directory object */ #endif #if FF_FS_REENTRANT - unlock_fs(fs, FR_OK); /* Unlock volume */ + unlock_volume(fs, FR_OK); /* Unlock volume */ #endif } return res; @@ -4637,7 +4703,7 @@ FRESULT f_readdir ( res = validate(&dp->obj, &fs); /* Check validity of the directory object */ if (res == FR_OK) { if (!fno) { - res = dir_sdi(dp, 0); /* Rewind the directory object */ + res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { INIT_NAMBUF(fs); res = DIR_READ_FILE(dp); /* Read an item */ @@ -4775,8 +4841,12 @@ FRESULT f_getfree ( clst = 2; obj.fs = fs; do { stat = get_fat(&obj, clst); - if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } - if (stat == 1) { res = FR_INT_ERR; break; } + if (stat == 0xFFFFFFFF) { + res = FR_DISK_ERR; break; + } + if (stat == 1) { + res = FR_INT_ERR; break; + } if (stat == 0) nfree++; } while (++clst < fs->n_fatent); } else { @@ -4789,12 +4859,12 @@ FRESULT f_getfree ( sect = fs->bitbase; /* Bitmap sector */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of bits with zero in the bitmap */ - if (i == 0) { + if (i == 0) { /* New sector? */ res = move_window(fs, sect++); if (res != FR_OK) break; } - for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { - if (!(bm & 1)) nfree++; + for (b = 8, bm = ~fs->win[i]; b && clst; b--, clst--) { + nfree += bm & 1; bm >>= 1; } i = (i + 1) % SS(fs); @@ -4806,7 +4876,7 @@ FRESULT f_getfree ( sect = fs->fatbase; /* Top of the FAT */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of entries with zero in the FAT */ - if (i == 0) { + if (i == 0) { /* New sector? */ res = move_window(fs, sect++); if (res != FR_OK) break; } @@ -4894,9 +4964,9 @@ FRESULT f_unlink ( ) { FRESULT res; + FATFS *fs; DIR dj, sdj; DWORD dclst = 0; - FATFS *fs; #if FF_FS_EXFAT FFOBJID obj; #endif @@ -4912,8 +4982,8 @@ FRESULT f_unlink ( if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; /* Cannot remove dot entry */ } -#if FF_FS_LOCK != 0 - if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ +#if FF_FS_LOCK + if (res == FR_OK) res = chk_share(&dj, 2); /* Check if it is an open object */ #endif if (res == FR_OK) { /* The object is accessible */ if (dj.fn[NSFLAG] & NS_NONAME) { @@ -4988,9 +5058,9 @@ FRESULT f_mkdir ( ) { FRESULT res; + FATFS *fs; DIR dj; FFOBJID sobj; - FATFS *fs; DWORD dcl, pcl, tm; DEF_NAMBUF @@ -5073,8 +5143,8 @@ FRESULT f_rename ( ) { FRESULT res; - DIR djo, djn; FATFS *fs; + DIR djo, djn; BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; LBA_t sect; DEF_NAMBUF @@ -5087,9 +5157,9 @@ FRESULT f_rename ( INIT_NAMBUF(fs); res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK if (res == FR_OK) { - res = chk_lock(&djo, 2); + res = chk_share(&djo, 2); } #endif if (res == FR_OK) { /* Object to be renamed is found */ @@ -5184,8 +5254,8 @@ FRESULT f_chmod ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; DEF_NAMBUF @@ -5230,8 +5300,8 @@ FRESULT f_utime ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; DEF_NAMBUF @@ -5278,8 +5348,8 @@ FRESULT f_getlabel ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; UINT si, di; WCHAR wc; @@ -5304,7 +5374,9 @@ FRESULT f_getlabel ( hs = wc; continue; } nw = put_utf((DWORD)hs << 16 | wc, &label[di], 4); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Encode error? */ + if (nw == 0) { /* Encode error? */ + di = 0; break; + } di += nw; hs = 0; } @@ -5319,7 +5391,9 @@ FRESULT f_getlabel ( #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ - if (wc == 0) { di = 0; break; } /* Invalid char in current code page? */ + if (wc == 0) { /* Invalid char in current code page? */ + di = 0; break; + } di += put_utf(wc, &label[di], 4); /* Store it in Unicode */ #else /* ANSI/OEM output */ label[di++] = (TCHAR)wc; @@ -5373,8 +5447,8 @@ FRESULT f_setlabel ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; BYTE dirvn[22]; UINT di; WCHAR wc; @@ -5530,14 +5604,20 @@ FRESULT f_expand ( for (;;) { /* Find a contiguous cluster block */ n = get_fat(&fp->obj, clst); if (++clst >= fs->n_fatent) clst = 2; - if (n == 1) { res = FR_INT_ERR; break; } - if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (n == 1) { + res = FR_INT_ERR; break; + } + if (n == 0xFFFFFFFF) { + res = FR_DISK_ERR; break; + } if (n == 0) { /* Is it a free cluster? */ if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ } else { scl = clst; ncl = 0; /* Not a free cluster */ } - if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ + if (clst == stcl) { /* No contiguous cluster? */ + res = FR_DENIED; break; + } } if (res == FR_OK) { /* A contiguous free area is found */ if (opt) { /* Allocate it now */ @@ -5659,8 +5739,8 @@ FRESULT f_forward ( static FRESULT create_partition ( BYTE drv, /* Physical drive number */ const LBA_t plst[], /* Partition list */ - BYTE sys, /* System ID (for only MBR, temp setting) */ - BYTE* buf /* Working buffer for a sector */ + BYTE sys, /* System ID for each partition (for only MBR) */ + BYTE *buf /* Working buffer for a sector */ ) { UINT i, cy; @@ -5689,7 +5769,7 @@ static FRESULT create_partition ( rnd = (DWORD)sz_drv + GET_FATTIME(); /* Random seed */ align = GPT_ALIGN / ss; /* Partition alignment for GPT [sector] */ sz_ptbl = GPT_ITEMS * SZ_GPTE / ss; /* Size of partition table [sector] */ - top_bpt = sz_drv - sz_ptbl - 1; /* Backup partiiton table start sector */ + top_bpt = sz_drv - sz_ptbl - 1; /* Backup partition table start sector */ nxt_alloc = 2 + sz_ptbl; /* First allocatable sector */ sz_pool = top_bpt - nxt_alloc; /* Size of allocatable area */ bcc = 0xFFFFFFFF; sz_part = 1; @@ -5802,14 +5882,16 @@ static FRESULT create_partition ( FRESULT f_mkfs ( const TCHAR* path, /* Logical drive number */ const MKFS_PARM* opt, /* Format options */ - void* work, /* Pointer to working buffer (null: use heap memory) */ + void* work, /* Pointer to working buffer (null: use len bytes of heap memory) */ UINT len /* Size of working buffer [byte] */ ) { static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */ - BYTE fsopt, fsty, sys, *buf, *pte, pdrv, ipart; + BYTE fsopt, fsty, sys, pdrv, ipart; + BYTE *buf; + BYTE *pte; WORD ss; /* Sector size */ DWORD sz_buf, sz_blk, n_clst, pau, nsect, n, vsn; LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */ @@ -5818,30 +5900,33 @@ FRESULT f_mkfs ( UINT n_fat, n_root, i; /* Index, Number of FATs and Number of roor dir entries */ int vol; DSTATUS ds; - FRESULT fr; + FRESULT res; /* Check mounted drive and clear work area */ vol = get_ldnumber(&path); /* Get target logical drive */ if (vol < 0) return FR_INVALID_DRIVE; if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the fs object if mounted */ - pdrv = LD2PD(vol); /* Physical drive */ - ipart = LD2PT(vol); /* Partition (0:create as new, 1..:get from partition table) */ - if (!opt) opt = &defopt; /* Use default parameter if it is not given */ + pdrv = LD2PD(vol); /* Hosting physical drive */ + ipart = LD2PT(vol); /* Hosting partition (0:create as new, 1..:existing partition) */ - /* Get physical drive status (sz_drv, sz_blk, ss) */ + /* Initialize the hosting physical drive */ ds = disk_initialize(pdrv); if (ds & STA_NOINIT) return FR_NOT_READY; if (ds & STA_PROTECT) return FR_WRITE_PROTECTED; + + /* Get physical drive parameters (sz_drv, sz_blk and ss) */ + if (!opt) opt = &defopt; /* Use default parameter if it is not given */ sz_blk = opt->align; - if (sz_blk == 0 && disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK) sz_blk = 1; - if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; + if (sz_blk == 0) disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk); /* Block size from the paramter or lower layer */ + if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Use default if the block size is invalid */ #if FF_MAX_SS != FF_MIN_SS if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else ss = FF_MAX_SS; #endif + /* Options for FAT sub-type and FAT parameters */ fsopt = opt->fmt & (FM_ANY | FM_SFD); n_fat = (opt->n_fat >= 1 && opt->n_fat <= 2) ? opt->n_fat : 1; @@ -5957,7 +6042,7 @@ FRESULT f_mkfs ( sz_fat = (DWORD)((sz_vol / sz_au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~((LBA_t)sz_blk - 1); /* Align data area to the erase block boundary */ if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ - n_clst = (DWORD)(sz_vol - (b_data - b_vol)) / sz_au; /* Number of clusters */ + n_clst = (DWORD)((sz_vol - (b_data - b_vol)) / sz_au); /* Number of clusters */ if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ @@ -6258,32 +6343,30 @@ FRESULT f_mkfs ( /* Determine system ID in the MBR partition table */ if (FF_FS_EXFAT && fsty == FS_EXFAT) { - sys = 0x07; /* exFAT */ + sys = 0x07; /* exFAT */ + } else if (fsty == FS_FAT32) { + sys = 0x0C; /* FAT32X */ + } else if (sz_vol >= 0x10000) { + sys = 0x06; /* FAT12/16 (large) */ + } else if (fsty == FS_FAT16) { + sys = 0x04; /* FAT16 */ } else { - if (fsty == FS_FAT32) { - sys = 0x0C; /* FAT32X */ - } else { - if (sz_vol >= 0x10000) { - sys = 0x06; /* FAT12/16 (large) */ - } else { - sys = (fsty == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ - } - } + sys = 0x01; /* FAT12 */ } /* Update partition information */ if (FF_MULTI_PARTITION && ipart != 0) { /* Volume is in the existing partition */ - if (!FF_LBA64 || !(fsopt & 0x80)) { + if (!FF_LBA64 || !(fsopt & 0x80)) { /* Is the partition in MBR? */ /* Update system ID in the partition table */ if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ buf[MBR_Table + (ipart - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ } } else { /* Volume as a new single partition */ - if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD */ + if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD format */ lba[0] = sz_vol; lba[1] = 0; - fr = create_partition(pdrv, lba, sys, buf); - if (fr != FR_OK) LEAVE_MKFS(fr); + res = create_partition(pdrv, lba, sys, buf); + if (res != FR_OK) LEAVE_MKFS(res); } } @@ -6308,17 +6391,22 @@ FRESULT f_fdisk ( { BYTE *buf = (BYTE*)work; DSTATUS stat; + FRESULT res; + /* Initialize the physical drive */ stat = disk_initialize(pdrv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + #if FF_USE_LFN == 3 if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ #endif if (!buf) return FR_NOT_ENOUGH_CORE; - LEAVE_MKFS(create_partition(pdrv, ptbl, 0x07, buf)); + res = create_partition(pdrv, ptbl, 0x07, buf); /* Create partitions (system ID is temporary setting and determined by f_mkfs) */ + + LEAVE_MKFS(res); } #endif /* FF_MULTI_PARTITION */ @@ -6388,9 +6476,15 @@ TCHAR* f_gets ( dc = s[0]; if (dc >= 0x80) { /* Multi-byte sequence? */ ct = 0; - if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } /* 2-byte sequence? */ - if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } /* 3-byte sequence? */ - if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } /* 4-byte sequence? */ + if ((dc & 0xE0) == 0xC0) { /* 2-byte sequence? */ + dc &= 0x1F; ct = 1; + } + if ((dc & 0xF0) == 0xE0) { /* 3-byte sequence? */ + dc &= 0x0F; ct = 2; + } + if ((dc & 0xF8) == 0xF0) { /* 4-byte sequence? */ + dc &= 0x07; ct = 3; + } if (ct == 0) continue; f_read(fp, s, ct, &rc); /* Get trailing bytes */ if (rc != ct) break; @@ -6417,25 +6511,21 @@ TCHAR* f_gets ( *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ - } else { - if (dc < 0x800) { /* 2-byte sequence? */ - *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 2; - } else { - if (dc < 0x10000) { /* 3-byte sequence? */ - *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); - *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 3; - } else { /* 4-byte sequence? */ - *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); - *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 4; - } - } + } else if (dc < 0x800) { /* 2-byte sequence? */ + *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 2; + } else if (dc < 0x10000) { /* 3-byte sequence? */ + *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); + *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 3; + } else { /* 4-byte sequence */ + *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); + *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 4; } #endif } @@ -6493,7 +6583,7 @@ static void putc_bfd (putbuff* pb, TCHAR c) WCHAR hs, wc; #if FF_LFN_UNICODE == 2 DWORD dc; - const TCHAR *tp; + const TCHAR* tp; #endif #endif @@ -6507,39 +6597,39 @@ static void putc_bfd (putbuff* pb, TCHAR c) #if FF_USE_LFN && FF_LFN_UNICODE #if FF_LFN_UNICODE == 1 /* UTF-16 input */ - if (IsSurrogateH(c)) { /* High surrogate? */ + if (IsSurrogateH(c)) { /* Is this a high-surrogate? */ pb->hs = c; return; /* Save it for next */ } hs = pb->hs; pb->hs = 0; - if (hs != 0) { /* There is a leading high surrogate */ - if (!IsSurrogateL(c)) hs = 0; /* Discard high surrogate if not a surrogate pair */ + if (hs != 0) { /* Is there a leading high-surrogate? */ + if (!IsSurrogateL(c)) hs = 0; /* Discard high-surrogate if not a surrogate pair */ } else { - if (IsSurrogateL(c)) return; /* Discard stray low surrogate */ + if (IsSurrogateL(c)) return; /* Discard stray low-surrogate */ } wc = c; #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ for (;;) { if (pb->ct == 0) { /* Out of multi-byte sequence? */ pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ - if ((BYTE)c < 0x80) break; /* Single byte? */ + if ((BYTE)c < 0x80) break; /* Single byte code? */ if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte sequence? */ if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte sequence? */ - if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte sequence? */ - return; + if (((BYTE)c & 0xF8) == 0xF0) pb->ct = 3; /* 4-byte sequence? */ + return; /* Wrong leading byte (discard it) */ } else { /* In the multi-byte sequence */ if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ - pb->ct = 0; continue; + pb->ct = 0; continue; /* Discard the sequense */ } pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ - if (--pb->ct == 0) break; /* End of multi-byte sequence? */ + if (--pb->ct == 0) break; /* End of the sequence? */ return; } } tp = (const TCHAR*)pb->bs; - dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ + dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ if (dc == 0xFFFFFFFF) return; /* Wrong code? */ - wc = (WCHAR)dc; hs = (WCHAR)(dc >> 16); + wc = (WCHAR)dc; #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ if (IsSurrogate(c) || c >= 0x110000) return; /* Discard invalid code */ if (c >= 0x10000) { /* Out of BMP? */ @@ -6742,7 +6832,7 @@ static void ftoa ( er = "NaN"; } else { if (prec < 0) prec = 6; /* Default precision? (6 fractional digits) */ - if (val < 0) { /* Nagative? */ + if (val < 0) { /* Negative? */ val = 0 - val; sign = '-'; } else { sign = '+'; @@ -6790,7 +6880,9 @@ static void ftoa ( } if (er) { /* Error condition */ if (sign) *buf++ = sign; /* Add sign if needed */ - do *buf++ = *er++; while (*er); /* Put error symbol */ + do { /* Put error symbol */ + *buf++ = *er++; + } while (*er); } *buf = 0; /* Term */ } @@ -6813,7 +6905,8 @@ int f_printf ( #else DWORD v; #endif - TCHAR tc, pad, *tp; + TCHAR *tp; + TCHAR tc, pad; TCHAR nul = 0; char d, str[SZ_NUM_BUF]; @@ -6870,17 +6963,22 @@ int f_printf ( switch (tc) { /* Atgument type is... */ case 'b': /* Unsigned binary */ r = 2; break; + case 'o': /* Unsigned octal */ r = 8; break; + case 'd': /* Signed decimal */ - case 'u': /* Unsigned decimal */ + case 'u': /* Unsigned decimal */ r = 10; break; - case 'x': /* Unsigned hexdecimal (lower case) */ - case 'X': /* Unsigned hexdecimal (upper case) */ + + case 'x': /* Unsigned hexadecimal (lower case) */ + case 'X': /* Unsigned hexadecimal (upper case) */ r = 16; break; + case 'c': /* Character */ putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; + case 's': /* String */ tp = va_arg(arp, TCHAR*); /* Get a pointer argument */ if (!tp) tp = &nul; /* Null ptr generates a null string */ @@ -6894,7 +6992,7 @@ int f_printf ( case 'f': /* Floating point (decimal) */ case 'e': /* Floating point (e) */ case 'E': /* Floating point (E) */ - ftoa(str, va_arg(arp, double), prec, tc); /* Make a flaoting point string */ + ftoa(str, va_arg(arp, double), prec, tc); /* Make a floating point string */ for (j = strlen(str); !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ for (i = 0; str[i]; putc_bfd(&pb, str[i++])) ; /* Body */ while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ @@ -6906,14 +7004,12 @@ int f_printf ( /* Get an integer argument and put it in numeral */ #if FF_PRINT_LLI && FF_INTDEF == 2 - if (f & 8) { /* long long argument? */ - v = (QWORD)va_arg(arp, LONGLONG); - } else { - if (f & 4) { /* long argument? */ - v = (tc == 'd') ? (QWORD)(LONGLONG)va_arg(arp, long) : (QWORD)va_arg(arp, unsigned long); - } else { /* int/short/char argument */ - v = (tc == 'd') ? (QWORD)(LONGLONG)va_arg(arp, int) : (QWORD)va_arg(arp, unsigned int); - } + if (f & 8) { /* long long argument? */ + v = (QWORD)va_arg(arp, long long); + } else if (f & 4) { /* long argument? */ + v = (tc == 'd') ? (QWORD)(long long)va_arg(arp, long) : (QWORD)va_arg(arp, unsigned long); + } else { /* int/short/char argument */ + v = (tc == 'd') ? (QWORD)(long long)va_arg(arp, int) : (QWORD)va_arg(arp, unsigned int); } if (tc == 'd' && (v & 0x8000000000000000)) { /* Negative value? */ v = 0 - v; f |= 1; @@ -6936,9 +7032,15 @@ int f_printf ( } while (v && i < SZ_NUM_BUF); if (f & 1) str[i++] = '-'; /* Sign */ /* Write it */ - for (j = i; !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ - do putc_bfd(&pb, (TCHAR)str[--i]); while (i); /* Body */ - while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ + for (j = i; !(f & 2) && j < w; j++) { /* Left pads */ + putc_bfd(&pb, pad); + } + do { /* Body */ + putc_bfd(&pb, (TCHAR)str[--i]); + } while (i); + while (j++ < w) { /* Right pads */ + putc_bfd(&pb, ' '); + } } va_end(arp); @@ -6961,12 +7063,12 @@ FRESULT f_setcp ( ) { static const WORD validcp[22] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; - static const BYTE* const tables[22] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct855, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; + static const BYTE *const tables[22] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct855, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; UINT i; for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ - if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ + if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ CodePage = cp; if (cp >= 900) { /* DBCS */ diff --git a/stm-firmware/updater/ram-code/fatfs/ffsystem.c b/stm-firmware/updater/ram-code/fatfs/ffsystem.c index 6fe5621..170f101 100644 --- a/stm-firmware/updater/ram-code/fatfs/ffsystem.c +++ b/stm-firmware/updater/ram-code/fatfs/ffsystem.c @@ -1,170 +1,208 @@ /*------------------------------------------------------------------------*/ -/* Sample Code of OS Dependent Functions for FatFs */ -/* (C)ChaN, 2018 */ +/* A Sample Code of User Provided OS Dependent Functions for FatFs */ /*------------------------------------------------------------------------*/ - #include -#if FF_USE_LFN == 3 /* Dynamic memory allocation */ +#if FF_USE_LFN == 3 /* Use dynamic memory allocation */ /*------------------------------------------------------------------------*/ -/* Allocate a memory block */ +/* Allocate/Free a Memory Block */ /*------------------------------------------------------------------------*/ +#include /* with POSIX API */ + + void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ UINT msize /* Number of bytes to allocate */ ) { - return malloc(msize); /* Allocate a new memory block with POSIX API */ + return malloc((size_t)msize); /* Allocate a new memory block */ } -/*------------------------------------------------------------------------*/ -/* Free a memory block */ -/*------------------------------------------------------------------------*/ - void ff_memfree ( - void* mblock /* Pointer to the memory block to free (nothing to do if null) */ + void* mblock /* Pointer to the memory block to free (no effect if null) */ ) { - free(mblock); /* Free the memory block with POSIX API */ + free(mblock); /* Free the memory block */ } #endif + #if FF_FS_REENTRANT /* Mutal exclusion */ - /*------------------------------------------------------------------------*/ -/* Create a Synchronization Object */ +/* Definitions of Mutex */ /*------------------------------------------------------------------------*/ -/* This function is called in f_mount() function to create a new -/ synchronization object for the volume, such as semaphore and mutex. -/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR. -*/ -//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */ +#define OS_TYPE 0 /* 0:Win32, 1:uITRON4.0, 2:uC/OS-II, 3:FreeRTOS, 4:CMSIS-RTOS */ -int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ - BYTE vol, /* Corresponding volume (logical drive number) */ - FF_SYNC_t* sobj /* Pointer to return the created sync object */ -) -{ - /* Win32 */ - *sobj = CreateMutex(NULL, FALSE, NULL); - return (int)(*sobj != INVALID_HANDLE_VALUE); +#if OS_TYPE == 0 /* Win32 */ +#include +static HANDLE Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */ - /* uITRON */ -// T_CSEM csem = {TA_TPRI,1,1}; -// *sobj = acre_sem(&csem); -// return (int)(*sobj > 0); +#elif OS_TYPE == 1 /* uITRON */ +#include "itron.h" +#include "kernel.h" +static mtxid Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */ - /* uC/OS-II */ -// OS_ERR err; -// *sobj = OSMutexCreate(0, &err); -// return (int)(err == OS_NO_ERR); +#elif OS_TYPE == 2 /* uc/OS-II */ +#include "includes.h" +static OS_EVENT *Mutex[FF_VOLUMES + 1]; /* Table of mutex pinter */ - /* FreeRTOS */ -// *sobj = xSemaphoreCreateMutex(); -// return (int)(*sobj != NULL); +#elif OS_TYPE == 3 /* FreeRTOS */ +#include "FreeRTOS.h" +#include "semphr.h" +static SemaphoreHandle_t Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */ - /* CMSIS-RTOS */ -// *sobj = osMutexCreate(&Mutex[vol]); -// return (int)(*sobj != NULL); -} - - -/*------------------------------------------------------------------------*/ -/* Delete a Synchronization Object */ -/*------------------------------------------------------------------------*/ -/* This function is called in f_mount() function to delete a synchronization -/ object that created with ff_cre_syncobj() function. When a 0 is returned, -/ the f_mount() function fails with FR_INT_ERR. -*/ - -int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ - FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ -) -{ - /* Win32 */ - return (int)CloseHandle(sobj); - - /* uITRON */ -// return (int)(del_sem(sobj) == E_OK); - - /* uC/OS-II */ -// OS_ERR err; -// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); -// return (int)(err == OS_NO_ERR); - - /* FreeRTOS */ -// vSemaphoreDelete(sobj); -// return 1; - - /* CMSIS-RTOS */ -// return (int)(osMutexDelete(sobj) == osOK); -} - - -/*------------------------------------------------------------------------*/ -/* Request Grant to Access the Volume */ -/*------------------------------------------------------------------------*/ -/* This function is called on entering file functions to lock the volume. -/ When a 0 is returned, the file function fails with FR_TIMEOUT. -*/ - -int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ - FF_SYNC_t sobj /* Sync object to wait */ -) -{ - /* Win32 */ - return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); - - /* uITRON */ -// return (int)(wai_sem(sobj) == E_OK); - - /* uC/OS-II */ -// OS_ERR err; -// OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); -// return (int)(err == OS_NO_ERR); - - /* FreeRTOS */ -// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); - - /* CMSIS-RTOS */ -// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); -} - - -/*------------------------------------------------------------------------*/ -/* Release Grant to Access the Volume */ -/*------------------------------------------------------------------------*/ -/* This function is called on leaving file functions to unlock the volume. -*/ - -void ff_rel_grant ( - FF_SYNC_t sobj /* Sync object to be signaled */ -) -{ - /* Win32 */ - ReleaseMutex(sobj); - - /* uITRON */ -// sig_sem(sobj); - - /* uC/OS-II */ -// OSMutexPost(sobj); - - /* FreeRTOS */ -// xSemaphoreGive(sobj); - - /* CMSIS-RTOS */ -// osMutexRelease(sobj); -} +#elif OS_TYPE == 4 /* CMSIS-RTOS */ +#include "cmsis_os.h" +static osMutexId Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */ #endif + + +/*------------------------------------------------------------------------*/ +/* Create a Mutex */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount function to create a new mutex +/ or semaphore for the volume. When a 0 is returned, the f_mount function +/ fails with FR_INT_ERR. +*/ + +int ff_mutex_create ( /* Returns 1:Function succeeded or 0:Could not create the mutex */ + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + Mutex[vol] = CreateMutex(NULL, FALSE, NULL); + return (int)(Mutex[vol] != INVALID_HANDLE_VALUE); + +#elif OS_TYPE == 1 /* uITRON */ + T_CMTX cmtx = {TA_TPRI,1}; + + Mutex[vol] = acre_mtx(&cmtx); + return (int)(Mutex[vol] > 0); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OS_ERR err; + + Mutex[vol] = OSMutexCreate(0, &err); + return (int)(err == OS_NO_ERR); + +#elif OS_TYPE == 3 /* FreeRTOS */ + Mutex[vol] = xSemaphoreCreateMutex(); + return (int)(Mutex[vol] != NULL); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + osMutexDef(cmsis_os_mutex); + + Mutex[vol] = osMutexCreate(osMutex(cmsis_os_mutex)); + return (int)(Mutex[vol] != NULL); + +#endif +} + + +/*------------------------------------------------------------------------*/ +/* Delete a Mutex */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount function to delete a mutex or +/ semaphore of the volume created with ff_mutex_create function. +*/ + +void ff_mutex_delete ( /* Returns 1:Function succeeded or 0:Could not delete due to an error */ + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + CloseHandle(Mutex[vol]); + +#elif OS_TYPE == 1 /* uITRON */ + del_mtx(Mutex[vol]); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OS_ERR err; + + OSMutexDel(Mutex[vol], OS_DEL_ALWAYS, &err); + +#elif OS_TYPE == 3 /* FreeRTOS */ + vSemaphoreDelete(Mutex[vol]); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + osMutexDelete(Mutex[vol]); + +#endif +} + + +/*------------------------------------------------------------------------*/ +/* Request a Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on enter file functions to lock the volume. +/ When a 0 is returned, the file function fails with FR_TIMEOUT. +*/ + +int ff_mutex_take ( /* Returns 1:Succeeded or 0:Timeout */ + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + return (int)(WaitForSingleObject(Mutex[vol], FF_FS_TIMEOUT) == WAIT_OBJECT_0); + +#elif OS_TYPE == 1 /* uITRON */ + return (int)(tloc_mtx(Mutex[vol], FF_FS_TIMEOUT) == E_OK); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OS_ERR err; + + OSMutexPend(Mutex[vol], FF_FS_TIMEOUT, &err)); + return (int)(err == OS_NO_ERR); + +#elif OS_TYPE == 3 /* FreeRTOS */ + return (int)(xSemaphoreTake(Mutex[vol], FF_FS_TIMEOUT) == pdTRUE); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + return (int)(osMutexWait(Mutex[vol], FF_FS_TIMEOUT) == osOK); + +#endif +} + + + +/*------------------------------------------------------------------------*/ +/* Release a Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on leave file functions to unlock the volume. +*/ + +void ff_mutex_give ( + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + ReleaseMutex(Mutex[vol]); + +#elif OS_TYPE == 1 /* uITRON */ + unl_mtx(Mutex[vol]); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OSMutexPost(Mutex[vol]); + +#elif OS_TYPE == 3 /* FreeRTOS */ + xSemaphoreGive(Mutex[vol]); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + osMutexRelease(Mutex[vol]); + +#endif +} + +#endif /* FF_FS_REENTRANT */ + diff --git a/stm-firmware/updater/ram-code/fatfs/ffunicode.c b/stm-firmware/updater/ram-code/fatfs/ffunicode.c index c1d61b5..7c194c7 100644 --- a/stm-firmware/updater/ram-code/fatfs/ffunicode.c +++ b/stm-firmware/updater/ram-code/fatfs/ffunicode.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------*/ -/* Unicode handling functions for FatFs R0.13+ */ +/* Unicode Handling Functions for FatFs R0.13 and Later */ +/*------------------------------------------------------------------------*/ +/* This module will occupy a huge memory in the .rodata section when the */ +/* FatFs is configured for LFN with DBCS. If the system has a Unicode */ +/* library for the code conversion, this module should be modified to use */ +/* it to avoid silly memory consumption. */ /*------------------------------------------------------------------------*/ -/* This module will occupy a huge memory in the .const section when the / -/ FatFs is configured for LFN with DBCS. If the system has any Unicode / -/ utilitiy for the code conversion, this module should be modified to use / -/ that function to avoid silly memory consumption. / -/-------------------------------------------------------------------------*/ /* -/ Copyright (C) 2014, ChaN, all right reserved. +/ Copyright (C) 2022, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -22,10 +22,9 @@ / by use of this software. */ - #include -#if FF_USE_LFN /* This module will be blanked if non-LFN configuration */ +#if FF_USE_LFN != 0 /* This module will be blanked if in non-LFN configuration */ #define MERGE2(a, b) a ## b #define CVTBL(tbl, cp) MERGE2(tbl, cp) @@ -15214,8 +15213,8 @@ static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */ /*------------------------------------------------------------------------*/ -/* OEM <==> Unicode conversions for static code page configuration */ -/* SBCS fixed code page */ +/* OEM <==> Unicode Conversions for Static Code Page Configuration with */ +/* SBCS Fixed Code Page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 @@ -15225,7 +15224,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ ) { WCHAR c = 0; - const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); + const WCHAR* p = CVTBL(uc, FF_CODE_PAGE); if (uni < 0x80) { /* ASCII? */ @@ -15247,7 +15246,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ ) { WCHAR c = 0; - const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); + const WCHAR* p = CVTBL(uc, FF_CODE_PAGE); if (oem < 0x80) { /* ASCII? */ @@ -15267,8 +15266,8 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ /*------------------------------------------------------------------------*/ -/* OEM <==> Unicode conversions for static code page configuration */ -/* DBCS fixed code page */ +/* OEM <==> Unicode Conversions for Static Code Page Configuration with */ +/* DBCS Fixed Code Page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE >= 900 @@ -15277,7 +15276,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0, uc; UINT i = 0, n, li, hi; @@ -15313,7 +15312,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0; UINT i = 0, n, li, hi; @@ -15346,7 +15345,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ /*------------------------------------------------------------------------*/ -/* OEM <==> Unicode conversions for dynamic code page configuration */ +/* OEM <==> Unicode Conversions for Dynamic Code Page Configuration */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE == 0 @@ -15360,7 +15359,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0, uc; UINT i, n, li, hi; @@ -15412,7 +15411,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0; UINT i, n, li, hi; @@ -15458,14 +15457,14 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ /*------------------------------------------------------------------------*/ -/* Unicode up-case conversion */ +/* Unicode Up-case Conversion */ /*------------------------------------------------------------------------*/ DWORD ff_wtoupper ( /* Returns up-converted code point */ DWORD uni /* Unicode code point to be up-converted */ ) { - const WORD *p; + const WORD* p; WORD uc, bc, nc, cmd; static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ /* Basic Latin */ @@ -15590,4 +15589,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */ } -#endif /* #if FF_USE_LFN */ +#endif /* #if FF_USE_LFN != 0 */ diff --git a/stm-firmware/updater/ram-code/include/fatfs/ff.h b/stm-firmware/updater/ram-code/include/fatfs/ff.h index 64bf79d..d88febc 100644 --- a/stm-firmware/updater/ram-code/include/fatfs/ff.h +++ b/stm-firmware/updater/ram-code/include/fatfs/ff.h @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem module R0.14b / +/ FatFs - Generic FAT Filesystem module R0.15 / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2021, ChaN, all right reserved. +/ Copyright (C) 2022, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -20,7 +20,7 @@ #ifndef FF_DEFINED -#define FF_DEFINED 86631 /* Revision ID */ +#define FF_DEFINED 80286 /* Revision ID */ #ifdef __cplusplus extern "C" { @@ -131,10 +131,11 @@ extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ typedef struct { BYTE fs_type; /* Filesystem type (0:not mounted) */ - BYTE pdrv; /* Associated physical drive */ + BYTE pdrv; /* Volume hosting physical drive */ + BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */ BYTE n_fats; /* Number of FATs (1 or 2) */ - BYTE wflag; /* win[] flag (b0:dirty) */ - BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ + BYTE wflag; /* win[] status (b0:dirty) */ + BYTE fsi_flag; /* FSINFO status (b7:disabled, b0:dirty) */ WORD id; /* Volume mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD csize; /* Cluster size [sectors] */ @@ -147,9 +148,6 @@ typedef struct { #if FF_FS_EXFAT BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ #endif -#if FF_FS_REENTRANT - FF_SYNC_t sobj; /* Identifier of sync object */ -#endif #if !FF_FS_READONLY DWORD last_clst; /* Last allocated cluster */ DWORD free_clst; /* Number of free clusters */ @@ -163,10 +161,10 @@ typedef struct { #endif #endif DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ - DWORD fsize; /* Size of an FAT [sectors] */ + DWORD fsize; /* Number of sectors per FAT */ LBA_t volbase; /* Volume base sector */ LBA_t fatbase; /* FAT base sector */ - LBA_t dirbase; /* Root directory base sector/cluster */ + LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */ LBA_t database; /* Data base sector */ #if FF_FS_EXFAT LBA_t bitbase; /* Allocation bitmap base sector */ @@ -181,7 +179,7 @@ typedef struct { typedef struct { FATFS* fs; /* Pointer to the hosting volume of this object */ - WORD id; /* Hosting volume mount ID */ + WORD id; /* Hosting volume's mount ID */ BYTE attr; /* Object attribute */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ @@ -250,7 +248,7 @@ typedef struct { WORD ftime; /* Modified time */ BYTE fattrib; /* File attribute */ #if FF_USE_LFN - TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ + TCHAR altname[FF_SFN_BUF + 1];/* Alternative file name */ TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ #else TCHAR fname[12 + 1]; /* File name */ @@ -298,8 +296,10 @@ typedef enum { + +/*--------------------------------------------------------------*/ +/* FatFs Module Application Interface */ /*--------------------------------------------------------------*/ -/* FatFs module application interface */ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_close (FIL* fp); /* Close an open file object */ @@ -336,6 +336,8 @@ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ +/* Some API fucntions are implemented as macro */ + #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) #define f_tell(fp) ((fp)->fptr) @@ -349,38 +351,43 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil /*--------------------------------------------------------------*/ -/* Additional user defined functions */ +/* Additional Functions */ +/*--------------------------------------------------------------*/ -/* RTC function */ +/* RTC function (provided by user) */ #if !FF_FS_READONLY && !FF_FS_NORTC -DWORD get_fattime (void); +DWORD get_fattime (void); /* Get current time */ #endif -/* LFN support functions */ -#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ + +/* LFN support functions (defined in ffunicode.c) */ + +#if FF_USE_LFN >= 1 WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ #endif -#if FF_USE_LFN == 3 /* Dynamic memory allocation */ -void* ff_memalloc (UINT msize); /* Allocate memory block */ -void ff_memfree (void* mblock); /* Free memory block */ -#endif -/* Sync functions */ -#if FF_FS_REENTRANT -int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ -int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ -void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ -int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ + +/* O/S dependent functions (samples available in ffsystem.c) */ + +#if FF_USE_LFN == 3 /* Dynamic memory allocation */ +void* ff_memalloc (UINT msize); /* Allocate memory block */ +void ff_memfree (void* mblock); /* Free memory block */ +#endif +#if FF_FS_REENTRANT /* Sync functions */ +int ff_mutex_create (int vol); /* Create a sync object */ +void ff_mutex_delete (int vol); /* Delete a sync object */ +int ff_mutex_take (int vol); /* Lock sync object */ +void ff_mutex_give (int vol); /* Unlock sync object */ #endif /*--------------------------------------------------------------*/ -/* Flags and offset address */ - +/* Flags and Offset Address */ +/*--------------------------------------------------------------*/ /* File access mode and open method flags (3rd argument of f_open) */ #define FA_READ 0x01 diff --git a/stm-firmware/updater/ram-code/include/fatfs/ffconf.h b/stm-firmware/updater/ram-code/include/fatfs/ffconf.h index 78c447c..3788467 100644 --- a/stm-firmware/updater/ram-code/include/fatfs/ffconf.h +++ b/stm-firmware/updater/ram-code/include/fatfs/ffconf.h @@ -1,8 +1,8 @@ /*---------------------------------------------------------------------------/ -/ FatFs Functional Configurations +/ Configurations of FatFs Module /---------------------------------------------------------------------------*/ -#define FFCONF_DEF 86631 /* Revision ID */ +#define FFCONF_DEF 80286 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -68,7 +68,7 @@ / 2: Enable with LF-CRLF conversion. / / FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 - makes f_printf() support floating point argument. These features want C99 or later. +/ makes f_printf() support floating point argument. These features want C99 or later. / When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character / encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE / to be read/written via those functions. @@ -178,7 +178,7 @@ / logical drives. Number of items must not be less than FF_VOLUMES. Valid / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is -/ not defined, a user defined volume string table needs to be defined as: +/ not defined, a user defined volume string table is needed as: / / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... */ @@ -190,7 +190,7 @@ / number and only an FAT volume found on the physical drive will be mounted. / When this function is enabled (1), each logical drive number can be bound to / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() -/ funciton will be available. */ +/ function will be available. */ #define FF_MIN_SS 512 @@ -240,10 +240,10 @@ #define FF_FS_NORTC 0 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 -#define FF_NORTC_YEAR 2020 -/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have -/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable -/ the timestamp function. Every object modified by FatFs will have a fixed timestamp +#define FF_NORTC_YEAR 2022 +/* The option FF_FS_NORTC switches timestamp feature. If the system does not have +/ an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the +/ timestamp feature. Every object modified by FatFs will have a fixed timestamp / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / added to the project to read current time form real-time clock. FF_NORTC_MON, @@ -253,7 +253,7 @@ #define FF_FS_NOFSINFO 0 /* If you need to know correct free space on the FAT32 volume, set bit 0 of this -/ option, and f_getfree() function at first time after volume mount will force +/ option, and f_getfree() function at the first time after volume mount will force / a full FAT scan. Bit 1 controls the use of last allocated cluster number. / / bit0=0: Use free cluster count in the FSINFO if available. @@ -275,26 +275,21 @@ / lock control is independent of re-entrancy. */ -/* #include // O/S definitions */ #define FF_FS_REENTRANT 0 #define FF_FS_TIMEOUT 1000 -#define FF_SYNC_t HANDLE /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / and f_fdisk() function, are always not re-entrant. Only file/directory access -/ to the same volume is under control of this function. +/ to the same volume is under control of this featuer. / -/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. +/ 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, -/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() -/ function, must be added to the project. Samples are available in -/ option/syscall.c. +/ ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give() +/ function, must be added to the project. Samples are available in ffsystem.c. / -/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. -/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, -/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be -/ included somewhere in the scope of ff.h. */ +/ The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick. +*/ diff --git a/stm-firmware/version.c b/stm-firmware/version.c new file mode 100644 index 0000000..602a0ef --- /dev/null +++ b/stm-firmware/version.c @@ -0,0 +1,27 @@ +/* Reflow Oven Controller + * + * Copyright (C) 2022 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 + +const char *version_git_version_string = GIT_VERSION_STRING; +const char *version_git_full_commit_string = GIT_FULL_COMMIT; +const char *version_compile_date = __DATE__; +const char *version_compile_time = __TIME__; \ No newline at end of file