Merge branch 'main' into LCD_API

This commit is contained in:
2023-11-09 15:01:36 +01:00
24 changed files with 5061 additions and 184 deletions

10
.gitignore vendored
View File

@@ -37,4 +37,12 @@ project/.idea/
project/cmake-build-debug/
project/Scripts/
project/.settings/
project/.mxproject
project/project.launch
project/.cproject
project/Scripts

150
README.md
View File

@@ -1,21 +1,29 @@
# 2023-Webservices_And_Applications
## Used Libs, compiler and apps
- lwip version 2.1.2
- CubeIDE version 1.12.1
- STM32CubeMX version 6.8.1
- Firmware Lib (stm32f7) 1.17.1
# 2023Webservices and Applications
## Table of Contents
- [Table of Contents](#table-of-contents)
- [Used Libs, compiler and apps](#used-libs-compiler-and-apps)
- [Tasks](#tasks)
- [Style Guide](#style-guide)
- [Editor Configuration](#editor-configuration)
- [Commit Messages Conventions](#commit-messages-conventions)
- [Documentation](#documentation)
## Tasks
Make for each task a sperate c and h file. The name of the file is the name of the task.
This way we can keep the code clean.
[tasks_and_taskowners.md](tasks_and_taskowners.md)
## Used Libs, Compiler and Apps
- lwip version 2.1.2
- CubeIDE version 1.12.1
- STM32CubeMX version 6.8.1
- Firmware Lib (stm32f7) 1.17.1
## Tasks
Make for each task a separate c and h file. The name of the file is the name of the task.
This way we can keep the code clean.
[tasks_and_taskowners.md](tasks_and_taskowners.md)
## Style Guide
To maintain a consistent and clean codebase, follow the [style guide](style_guide.md). This document provides detailed instructions on naming conventions, code structure, and commenting practices.
To maintain a consistent and clean codebase, follow the [style guide](docs/style_guide.md). This document provides detailed instructions on naming conventions, code structure, and commenting practices.
Please read the [style_guide.md](style_guide.md) carefully before making contributions.
Please read the [style_guide.md](docs/style_guide.md) carefully before making contributions.
### Editor Configuration
@@ -30,106 +38,26 @@ You can choose from the following options:
- For Eclipse-based editors, including STM32CubeIDE.
- You can import it within eclipse settings, `Preferences -> LANGUAGE -> Code Style -> Formatter` tab.
## Logging and Debugging Messages
The logging system is designed to make log messages clearer and improve their uniformity across the project.
It makes it easier to see where a log message comes from and what its verbosity is.
## Commit Messages Conventions
The subject line of a commit message should follow the following rules:
- Short and descriptive (max 50 chars)
- In imperative present tense
- Capitalized
- Not end with a period
To use the logging system, include `log.h` in your source file, and use the following macros to print log messages:
```c
LOG_DEBUG(TAG, fmt, ...)
LOG_INFO(TAG, fmt, ...)
LOG_WARN(TAG, fmt, ...)
LOG_CRIT(TAG, fmt, ...)
LOG_FATAL(TAG, fmt, ...)
Example:
```
The same format specifiers as in `printf` can be used.
The `TAG` parameter is a string that identifies the source of the log message.
It is recommended to use one tag for each source file / module, and to name the tag after the source file / module.
See the example below.
### Global Log Level
You can control the verbosity of the logging output by setting a global log level in `log.h`.
This log level filters out messages with a lower priority.
### Custom Log Levels
before you include `log.h`, you can define custom log levels by defining the following macros:
```c
// All log messages will be printed
#define LOGGER_LEVEL_ALL
#include "log.h"
Implement access right management
```
```c
// Info and higher priority messages will be printed
#define LOGGER_LEVEL_INFO
#include "log.h"
```
The body of a commit message may be used to explain the what and why of a commit.
```c
// Only warnings and errors will be printed
#define LOGGER_LEVEL_WARN
#include "log.h"
```
## Documentation
Documentation is placed in the [docs](docs) folder.
If your part needs documentation (e.g. how to use tcp cmd interface), add a markdown file in the above-mentioned folder.
```c
// Only log messages with level ERROR will be printed
#define LOGGER_LEVEL_CRITICAL
#include "log.h"
```
```c
// Only log messages with level ERROR will be printed
#define LOGGER_LEVEL_FATAL
#include "log.h"
```
### Colorful Log Messages
For improved readability, log messages can be printed in color by defining `LOGGER_USE_COLOR` in `log.h` or before you include `log.h`. \
Default is `0`
### Log Output Format
Each log entry is formatted to include the following information:
- Log level ([Debug], [Info], [Warn], [Critical], [Fatal])
- Timestamp (in milliseconds since boot)
- Tag
- The log message
For instance, a log entry may look like this:
`[Info] (2009) [LTDC]: This is a log message`
### Example
```c
#define LOGGER_LEVEL_INFO
#include "log.h"
// Don't use a define for the tag, as the pointer to the tag is used
static const char *TAG = "main";
int main(void) {
LOG_DEBUG(TAG, "This message will not be printed");
LOG_INFO(TAG, "This message will be printed");
LOG_WARN(TAG, "This message will be printed");
LOG_CRIT(TAG, "This message will be printed");
LOG_FATAL(TAG, "This message will be printed");
for (int i = 0; i < 3; i++) {
LOG_INFO(TAG, "Iteration %d of %d", i, 3);
}
return 0;
}
```
Result:
```
[Info] (2009) main: This message will be printed
[Warning] (2026) main: This message will be printed
[CRITICAL] (2033) main: This message will be printed
[FATAL] (2040) main: This message will be printed
[Info] (2040) main: Iteration 0 of 3
[Info] (2047) main: Iteration 1 of 3
[Info] (2054) main: Iteration 2 of 3
```
This folder contains the following documents:
- [llfs.md](docs/llfs.md): Linked List File System
- [logger.md](docs/logger.md): Logging and Debugging Messages
- [mkllfs.md](docs/mkllfs.md): Make Linked List File System
- [style_guide.md](docs/style_guide.md): Style Guide

57
docs/llfs.md Normal file
View File

@@ -0,0 +1,57 @@
# LLFS (Linked List File System)
## Introduction
The llfs filesystem can be generated using the mkllfss utility.
It is a simple filesystem that uses a linked list to store files.
The filesystem is stored in a single c file (`llfs_data.c`), which can be compiled and read by the llfs library.
The llfs filesystem is a flat filesystem, meaning that it does not support directories.
## Usage of the llfs API
### Getting a list of files
```c
#include "llfs.h"
void main(void) {
// Allocate space for 10 files
llfs_file_t file_list[10];
// Get the file list
size_t file_count = llfs_file_list(file_list, 10, NULL);
// Loop through the files and print their names and sizes
for (int i = 0; i < file_count; i++) {
LOG_INFO(TAG, "File: %s, size: %d", file_list[i].name, file_list[i].len);
}
}
```
Result:
```
[Info] (2009) [main]: File: image.bmp, size: 9270
[Info] (2013) [main]: File: python_file.py, size: 645
[Info] (2019) [main]: File: image2.bmp, size: 7738
[Info] (2024) [main]: File: filename with a space.txt, size: 61
[Info] (2031) [main]: File: file1.txt, size: 77
```
### Reading a file
```c
#include "llfs.h"
void main(void) {
// Get a file by name
llfs_file_t *file = llfs_file_open("filename with a space.txt");
if (file != NULL) {
// Print the file name, size and data
LOG_INFO(TAG, "File found: %s, size: %d", file->name, file->len);
LOG_INFO(TAG, "File data: %s", file->data);
} else {
LOG_WARN(TAG, "File not found");
}
}
```
Result:
```
[Info] (2040) [main]: File found: filename with a space.txt, size: 61
[Info] (2047) [main]: File data: This is a file with a space in it's filename.
```

103
docs/logger.md Normal file
View File

@@ -0,0 +1,103 @@
# Logging and Debugging Messages
The logging system is designed to make log messages clearer and improve their uniformity across the project.
It makes it easier to see where a log message comes from and what its verbosity is.
To use the logging system, include `log.h` in your source file, and use the following macros to print log messages:
```c
LOG_DEBUG(TAG, fmt, ...)
LOG_INFO(TAG, fmt, ...)
LOG_WARN(TAG, fmt, ...)
LOG_CRIT(TAG, fmt, ...)
LOG_FATAL(TAG, fmt, ...)
```
The same format specifiers as in `printf` can be used.
The `TAG` parameter is a string that identifies the source of the log message.
It is recommended to use one tag for each source file / module, and to name the tag after the source file / module.
See the example below.
## Global Log Level
You can control the verbosity of the logging output by setting a global log level in `log.h`.
This log level filters out messages with a lower priority.
## Custom Log Levels
before you include `log.h`, you can define custom log levels by defining the following macros:
```c
// All log messages will be printed
#define LOGGER_LEVEL_ALL
#include "log.h"
```
```c
// Info and higher priority messages will be printed
#define LOGGER_LEVEL_INFO
#include "log.h"
```
```c
// Only warnings and errors will be printed
#define LOGGER_LEVEL_WARN
#include "log.h"
```
```c
// Only log messages with level ERROR will be printed
#define LOGGER_LEVEL_CRITICAL
#include "log.h"
```
```c
// Only log messages with level ERROR will be printed
#define LOGGER_LEVEL_FATAL
#include "log.h"
```
## Colorful Log Messages
For improved readability, log messages can be printed in color by defining `LOGGER_USE_COLOR` in `log.h` or before you include `log.h`. \
Default is `0`
## Log Output Format
Each log entry is formatted to include the following information:
- Log level ([Debug], [Info], [Warn], [Critical], [Fatal])
- Timestamp (in milliseconds since boot)
- Tag
- The log message
For instance, a log entry may look like this:
`[Info] (2009) [LTDC]: This is a log message`
## Example
```c
#define LOGGER_LEVEL_INFO
#include "log.h"
// Don't use a define for the tag, as the pointer to the tag is used
static const char *TAG = "main";
int main(void) {
LOG_DEBUG(TAG, "This message will not be printed");
LOG_INFO(TAG, "This message will be printed");
LOG_WARN(TAG, "This message will be printed");
LOG_CRIT(TAG, "This message will be printed");
LOG_FATAL(TAG, "This message will be printed");
for (int i = 0; i < 3; i++) {
LOG_INFO(TAG, "Iteration %d of %d", i, 3);
}
return 0;
}
```
Result:
```
[Info] (2009) [main]: This message will be printed
[Warning] (2026) [main]: This message will be printed
[CRITICAL] (2033) [main]: This message will be printed
[FATAL] (2040) [main]: This message will be printed
[Info] (2040) [main]: Iteration 0 of 3
[Info] (2047) [main]: Iteration 1 of 3
[Info] (2054) [main]: Iteration 2 of 3
```

33
docs/mkllfs.md Normal file
View File

@@ -0,0 +1,33 @@
# MKLLFS (Make Linked List File System)
## Introduction
The llfs filesystem can be generated using the mkllfss utility. It is a simple filesystem that uses a linked list to store files.
The filesystem is stored in a single c file (llfs_data.c), which can be compiled and read by the llfs library.
The llfs filesystem is a flat filesystem, meaning that it does not support directories.
The mkllfs utilit can be used to generate the `llfs_data.c` file. The `llfs_data.c` file from a directory with files.
## Usage
The mkllfs utility can be used as follows:
```bash
mkllfs [options] <directory> <output_file>
```
For example:
```bash
mkllfs data llfs_data.c
```
Available options:
```
-h, --help show the help message and exit
-v, --version print the version of mkllfs and the llfs library that it generates for
```
## Building
The mkllfs utility can be built using the following command:
```bash
gcc -o mkllfs mkllfs.c
```
For windows, you can use the following command:
```bash
gcc -o mkllfs.exe mkllfs.c
```

2
mkllfs/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
cmake-build-debug
.idea

6
mkllfs/CMakeLists.txt Normal file
View File

@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.26)
project(mkllfs C)
set(CMAKE_C_STANDARD 11)
add_executable(mkllfs main.c)

187
mkllfs/main.c Normal file
View File

@@ -0,0 +1,187 @@
/**
* @file main.c
* @brief Converts files to a C file that can be used by llfs (linked list file system).
* @version 0.1.0
* @author Lorenz C.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tinydir.h"
#define VERSION "0.1.0"
#define LLFS_VERSION "0.1.0"
#define MAX_PATH_LEN 256
static void file_name_to_llfs_name(char* llfs_name, const char* file_name);
static void print_help(void);
static void print_version(void);
int main(int argc, char** argv) {
char src_path[MAX_PATH_LEN];
char llfs_name[MAX_PATH_LEN];
char prev_llfs_name[MAX_PATH_LEN] = "NULL";
FILE* out_file;
FILE* src_file;
tinydir_dir dir;
int file_count = 0;
// Check if the help or version flag is set
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
print_help();
return 0;
} else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
print_version();
return 0;
}
}
// Check if at least 2 arguments are given (directory and output file)
if (argc < 3) {
fprintf(stderr, "Error: Not enough arguments.\r\n");
print_help();
goto fail_init;
}
// Open the output file
out_file = fopen(argv[argc - 1], "w");
if (out_file == NULL) {
fprintf(stderr, "Error: Could not open output file\r\n");
goto fail_init;
}
// Open the source directory
strcpy(src_path, argv[argc - 2]);
if (tinydir_open(&dir, src_path) == -1) {
fprintf(stderr, "Error: Could not open directory\r\n");
goto fail_open_dir;
}
// Write the header of the output file
fprintf(out_file, "/**\n"
" * @file %s\n"
" * @brief Linked list file system (llfs) data file.\n"
" * This file was generated by mkllfs %s.\n"
" * @date %s\n */\n\n",
argv[argc - 1], VERSION, __DATE__);
// Write the headers of the output file
fprintf(out_file, "#include <stddef.h>\n");
fprintf(out_file, "#include \"llfs.h\"\n");
fprintf(out_file, "\n");
// Iterate over all files in the directory
while (dir.has_next) {
tinydir_file file;
size_t file_size = 0;
// Get file info
if (tinydir_readfile(&dir, &file) == -1) {
fprintf(stderr, "Error: Could not read file\r\n");
continue;
}
if (file.is_dir) {
tinydir_next(&dir);
continue;
}
// Open the source file
src_file = fopen(file.path, "rb");
if (src_file == NULL) {
printf("Error: Could not open source file: %s\r\n", file.path);
continue;
}
// Convert the file name to a valid llfs name
file_name_to_llfs_name(llfs_name, file.name);
// Write the file data to the output file
fprintf(out_file, "// File: %s\n", file.name);
fprintf(out_file, "const uint8_t %s_data[] = {\n", llfs_name);
for (int i = 0, c; (c = fgetc(src_file)) != EOF; i++) {
file_size++;
fprintf(out_file, "0x%02X, ", c);
if (i % 16 == 15) {
fprintf(out_file, "\n");
}
}
fprintf(out_file, "\n};\n");
// Write the file info to the output file
fprintf(out_file,
"const struct llfs_data_file %s = {\n .data = %s_data,\n .name = \"%s\",\n .len = %zu,\n "
".next =%s%s\n};\n\n",
llfs_name, llfs_name, file.name, file_size, strcmp(prev_llfs_name, "NULL") == 0 ? " " : " &",
prev_llfs_name);
file_count++;
tinydir_next(&dir);
strcpy(prev_llfs_name, llfs_name);
fclose(src_file);
}
// Make the last file the root file of the llfs
fprintf(out_file, "\n");
fprintf(out_file, "const struct llfs_data_file *llfs_root = &%s;\n", prev_llfs_name);
// Print the number of files
printf("Successfully converted %d files.\r\n", file_count);
fail:
tinydir_close(&dir);
fail_open_dir:
fclose(out_file);
fail_init:
return 0;
}
/**
* @brief Converts a file name to a valid llfs name, so that it can be used as a variable name in the generated C file.
* The length of the generated llfs name is the same as the length of the original file name.
*
* @param[out] llfs_name The output llfs name. Must be at least as long as the file name.
* @param[in] file_name The input file name as a null terminated string.
*/
static void file_name_to_llfs_name(char* llfs_name, const char* file_name) {
size_t len = strlen(file_name);
// Replace all invalid characters with '_'
for (int i = 0; i < len; i++) {
if (file_name[i] == '.' || file_name[i] == '-' || file_name[i] == ' ') {
llfs_name[i] = '_';
} else {
llfs_name[i] = file_name[i];
}
}
// Replace the first character if it is a number
if (llfs_name[0] >= '0' && llfs_name[0] <= '9') {
llfs_name[0] = '_';
}
llfs_name[len] = '\0';
}
/**
* @brief Prints the help message.
*/
static void print_help(void) {
printf("Make Linked list file system (mkllfs)\r\n");
printf("Converts files into a linked list file system.\r\n");
printf("By Lorenz C.\r\n");
printf("\r\n");
printf("Usage: mkllfs [options] <directory> <output file>\r\n");
printf("Options:\r\n");
printf(" -h, --help: Print this help message\r\n");
printf(" -v, --version: Print the version\r\n");
}
/**
* @brief Prints the version.
*/
static void print_version(void) {
printf("mkllfs version %s\r\n", VERSION);
printf("llfs version %s\r\n", LLFS_VERSION);
}

838
mkllfs/tinydir.h Normal file
View File

@@ -0,0 +1,838 @@
/*
Copyright (c) 2013-2021, tinydir authors:
- Cong Xu
- Lautis Sun
- Baudouin Feildel
- Andargor <andargor@yahoo.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TINYDIR_H
#define TINYDIR_H
#ifdef __cplusplus
extern "C" {
#endif
#if ((defined _UNICODE) && !(defined UNICODE))
#define UNICODE
#endif
#if ((defined UNICODE) && !(defined _UNICODE))
#define _UNICODE
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
# include <tchar.h>
# pragma warning(push)
# pragma warning (disable : 4996)
#else
# include <dirent.h>
# include <libgen.h>
# include <sys/stat.h>
# include <stddef.h>
#endif
#ifdef __MINGW32__
# include <tchar.h>
#endif
/* types */
/* Windows UNICODE wide character support */
#if defined _MSC_VER || defined __MINGW32__
# define _tinydir_char_t TCHAR
# define TINYDIR_STRING(s) _TEXT(s)
# define _tinydir_strlen _tcslen
# define _tinydir_strcpy _tcscpy
# define _tinydir_strcat _tcscat
# define _tinydir_strcmp _tcscmp
# define _tinydir_strrchr _tcsrchr
# define _tinydir_strncmp _tcsncmp
#else
# define _tinydir_char_t char
# define TINYDIR_STRING(s) s
# define _tinydir_strlen strlen
# define _tinydir_strcpy strcpy
# define _tinydir_strcat strcat
# define _tinydir_strcmp strcmp
# define _tinydir_strrchr strrchr
# define _tinydir_strncmp strncmp
#endif
#if (defined _MSC_VER || defined __MINGW32__)
# include <windows.h>
# define _TINYDIR_PATH_MAX MAX_PATH
#elif defined __linux__
# include <limits.h>
# ifdef PATH_MAX
# define _TINYDIR_PATH_MAX PATH_MAX
# endif
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
# include <sys/param.h>
# if defined(BSD)
# include <limits.h>
# ifdef PATH_MAX
# define _TINYDIR_PATH_MAX PATH_MAX
# endif
# endif
#endif
#ifndef _TINYDIR_PATH_MAX
#define _TINYDIR_PATH_MAX 4096
#endif
#ifdef _MSC_VER
/* extra chars for the "\\*" mask */
# define _TINYDIR_PATH_EXTRA 2
#else
# define _TINYDIR_PATH_EXTRA 0
#endif
#define _TINYDIR_FILENAME_MAX 256
#if (defined _MSC_VER || defined __MINGW32__)
#define _TINYDIR_DRIVE_MAX 3
#endif
#ifdef _MSC_VER
# define _TINYDIR_FUNC static __inline
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
# define _TINYDIR_FUNC static __inline__
#elif defined(__cplusplus)
# define _TINYDIR_FUNC static inline
#elif defined(__GNUC__)
/* Suppress unused function warning */
# define _TINYDIR_FUNC __attribute__((unused)) static
#else
# define _TINYDIR_FUNC static
#endif
/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
#ifdef TINYDIR_USE_READDIR_R
/* readdir_r is a POSIX-only function, and may not be available under various
* environments/settings, e.g. MinGW. Use readdir fallback */
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
_POSIX_SOURCE
# define _TINYDIR_HAS_READDIR_R
#endif
#if _POSIX_C_SOURCE >= 200112L
# define _TINYDIR_HAS_FPATHCONF
# include <unistd.h>
#endif
#if _BSD_SOURCE || _SVID_SOURCE || \
(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
# define _TINYDIR_HAS_DIRFD
# include <sys/types.h>
#endif
#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
defined _PC_NAME_MAX
# define _TINYDIR_USE_FPATHCONF
#endif
#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
# define _TINYDIR_USE_READDIR
#endif
/* Use readdir by default */
#else
# define _TINYDIR_USE_READDIR
#endif
/* MINGW32 has two versions of dirent, ASCII and UNICODE*/
#ifndef _MSC_VER
#if (defined __MINGW32__) && (defined _UNICODE)
#define _TINYDIR_DIR _WDIR
#define _tinydir_dirent _wdirent
#define _tinydir_opendir _wopendir
#define _tinydir_readdir _wreaddir
#define _tinydir_closedir _wclosedir
#else
#define _TINYDIR_DIR DIR
#define _tinydir_dirent dirent
#define _tinydir_opendir opendir
#define _tinydir_readdir readdir
#define _tinydir_closedir closedir
#endif
#endif
/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
#else
#error "Either define both alloc and free or none of them!"
#endif
#if !defined(_TINYDIR_MALLOC)
#define _TINYDIR_MALLOC(_size) malloc(_size)
#define _TINYDIR_FREE(_ptr) free(_ptr)
#endif /* !defined(_TINYDIR_MALLOC) */
typedef struct tinydir_file
{
_tinydir_char_t path[_TINYDIR_PATH_MAX];
_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
_tinydir_char_t *extension;
int is_dir;
int is_reg;
#ifndef _MSC_VER
#ifdef __MINGW32__
struct _stat _s;
#else
struct stat _s;
#endif
#endif
} tinydir_file;
typedef struct tinydir_dir
{
_tinydir_char_t path[_TINYDIR_PATH_MAX];
int has_next;
size_t n_files;
tinydir_file *_files;
#ifdef _MSC_VER
HANDLE _h;
WIN32_FIND_DATA _f;
#else
_TINYDIR_DIR *_d;
struct _tinydir_dirent *_e;
#ifndef _TINYDIR_USE_READDIR
struct _tinydir_dirent *_ep;
#endif
#endif
} tinydir_dir;
/* declarations */
_TINYDIR_FUNC
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
_TINYDIR_FUNC
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
_TINYDIR_FUNC
void tinydir_close(tinydir_dir *dir);
_TINYDIR_FUNC
int tinydir_next(tinydir_dir *dir);
_TINYDIR_FUNC
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
_TINYDIR_FUNC
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
_TINYDIR_FUNC
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
_TINYDIR_FUNC
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
_TINYDIR_FUNC
void _tinydir_get_ext(tinydir_file *file);
_TINYDIR_FUNC
int _tinydir_file_cmp(const void *a, const void *b);
#ifndef _MSC_VER
#ifndef _TINYDIR_USE_READDIR
_TINYDIR_FUNC
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
#endif
#endif
/* definitions*/
_TINYDIR_FUNC
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
{
#ifndef _MSC_VER
#ifndef _TINYDIR_USE_READDIR
int error;
int size; /* using int size */
#endif
#else
_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
#endif
_tinydir_char_t *pathp;
if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
{
errno = EINVAL;
return -1;
}
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
/* initialise dir */
dir->_files = NULL;
#ifdef _MSC_VER
dir->_h = INVALID_HANDLE_VALUE;
#else
dir->_d = NULL;
#ifndef _TINYDIR_USE_READDIR
dir->_ep = NULL;
#endif
#endif
tinydir_close(dir);
_tinydir_strcpy(dir->path, path);
/* Remove trailing slashes */
pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
{
*pathp = TINYDIR_STRING('\0');
pathp++;
}
#ifdef _MSC_VER
_tinydir_strcpy(path_buf, dir->path);
_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
#else
dir->_h = FindFirstFile(path_buf, &dir->_f);
#endif
if (dir->_h == INVALID_HANDLE_VALUE)
{
errno = ENOENT;
#else
dir->_d = _tinydir_opendir(path);
if (dir->_d == NULL)
{
#endif
goto bail;
}
/* read first file */
dir->has_next = 1;
#ifndef _MSC_VER
#ifdef _TINYDIR_USE_READDIR
dir->_e = _tinydir_readdir(dir->_d);
#else
/* allocate dirent buffer for readdir_r */
size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
if (size == -1) return -1;
dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
if (dir->_ep == NULL) return -1;
error = readdir_r(dir->_d, dir->_ep, &dir->_e);
if (error != 0) return -1;
#endif
if (dir->_e == NULL)
{
dir->has_next = 0;
}
#endif
return 0;
bail:
tinydir_close(dir);
return -1;
}
_TINYDIR_FUNC
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
{
/* Count the number of files first, to pre-allocate the files array */
size_t n_files = 0;
if (tinydir_open(dir, path) == -1)
{
return -1;
}
while (dir->has_next)
{
n_files++;
if (tinydir_next(dir) == -1)
{
goto bail;
}
}
tinydir_close(dir);
if (n_files == 0 || tinydir_open(dir, path) == -1)
{
return -1;
}
dir->n_files = 0;
dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
if (dir->_files == NULL)
{
goto bail;
}
while (dir->has_next)
{
tinydir_file *p_file;
dir->n_files++;
p_file = &dir->_files[dir->n_files - 1];
if (tinydir_readfile(dir, p_file) == -1)
{
goto bail;
}
if (tinydir_next(dir) == -1)
{
goto bail;
}
/* Just in case the number of files has changed between the first and
second reads, terminate without writing into unallocated memory */
if (dir->n_files == n_files)
{
break;
}
}
qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
return 0;
bail:
tinydir_close(dir);
return -1;
}
_TINYDIR_FUNC
void tinydir_close(tinydir_dir *dir)
{
if (dir == NULL)
{
return;
}
memset(dir->path, 0, sizeof(dir->path));
dir->has_next = 0;
dir->n_files = 0;
_TINYDIR_FREE(dir->_files);
dir->_files = NULL;
#ifdef _MSC_VER
if (dir->_h != INVALID_HANDLE_VALUE)
{
FindClose(dir->_h);
}
dir->_h = INVALID_HANDLE_VALUE;
#else
if (dir->_d)
{
_tinydir_closedir(dir->_d);
}
dir->_d = NULL;
dir->_e = NULL;
#ifndef _TINYDIR_USE_READDIR
_TINYDIR_FREE(dir->_ep);
dir->_ep = NULL;
#endif
#endif
}
_TINYDIR_FUNC
int tinydir_next(tinydir_dir *dir)
{
if (dir == NULL)
{
errno = EINVAL;
return -1;
}
if (!dir->has_next)
{
errno = ENOENT;
return -1;
}
#ifdef _MSC_VER
if (FindNextFile(dir->_h, &dir->_f) == 0)
#else
#ifdef _TINYDIR_USE_READDIR
dir->_e = _tinydir_readdir(dir->_d);
#else
if (dir->_ep == NULL)
{
return -1;
}
if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
{
return -1;
}
#endif
if (dir->_e == NULL)
#endif
{
dir->has_next = 0;
#ifdef _MSC_VER
if (GetLastError() != ERROR_SUCCESS &&
GetLastError() != ERROR_NO_MORE_FILES)
{
tinydir_close(dir);
errno = EIO;
return -1;
}
#endif
}
return 0;
}
_TINYDIR_FUNC
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
{
const _tinydir_char_t *filename;
if (dir == NULL || file == NULL)
{
errno = EINVAL;
return -1;
}
#ifdef _MSC_VER
if (dir->_h == INVALID_HANDLE_VALUE)
#else
if (dir->_e == NULL)
#endif
{
errno = ENOENT;
return -1;
}
filename =
#ifdef _MSC_VER
dir->_f.cFileName;
#else
dir->_e->d_name;
#endif
if (_tinydir_strlen(dir->path) +
_tinydir_strlen(filename) + 1 + _TINYDIR_PATH_EXTRA >=
_TINYDIR_PATH_MAX)
{
/* the path for the file will be too long */
errno = ENAMETOOLONG;
return -1;
}
if (_tinydir_strlen(filename) >= _TINYDIR_FILENAME_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
_tinydir_strcpy(file->path, dir->path);
if (_tinydir_strcmp(dir->path, TINYDIR_STRING("/")) != 0)
_tinydir_strcat(file->path, TINYDIR_STRING("/"));
_tinydir_strcpy(file->name, filename);
_tinydir_strcat(file->path, filename);
#ifndef _MSC_VER
#ifdef __MINGW32__
if (_tstat(
#elif (defined _BSD_SOURCE) || (defined _DEFAULT_SOURCE) \
|| ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) \
|| ((defined _POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \
|| ((defined __APPLE__) && (defined __MACH__)) \
|| (defined BSD)
if (lstat(
#else
if (stat(
#endif
file->path, &file->_s) == -1)
{
return -1;
}
#endif
_tinydir_get_ext(file);
file->is_dir =
#ifdef _MSC_VER
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
#else
S_ISDIR(file->_s.st_mode);
#endif
file->is_reg =
#ifdef _MSC_VER
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
(
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
#endif
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
#endif
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
#else
S_ISREG(file->_s.st_mode);
#endif
return 0;
}
_TINYDIR_FUNC
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
{
if (dir == NULL || file == NULL)
{
errno = EINVAL;
return -1;
}
if (i >= dir->n_files)
{
errno = ENOENT;
return -1;
}
memcpy(file, &dir->_files[i], sizeof(tinydir_file));
_tinydir_get_ext(file);
return 0;
}
_TINYDIR_FUNC
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
{
_tinydir_char_t path[_TINYDIR_PATH_MAX];
if (dir == NULL)
{
errno = EINVAL;
return -1;
}
if (i >= dir->n_files || !dir->_files[i].is_dir)
{
errno = ENOENT;
return -1;
}
_tinydir_strcpy(path, dir->_files[i].path);
tinydir_close(dir);
if (tinydir_open_sorted(dir, path) == -1)
{
return -1;
}
return 0;
}
/* Open a single file given its path */
_TINYDIR_FUNC
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
{
tinydir_dir dir;
int result = 0;
int found = 0;
_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
_tinydir_char_t *dir_name;
_tinydir_char_t *base_name;
#if (defined _MSC_VER || defined __MINGW32__)
_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
#endif
if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
{
errno = EINVAL;
return -1;
}
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
/* Get the parent path */
#if (defined _MSC_VER || defined __MINGW32__)
#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
errno = _tsplitpath_s(
path,
drive_buf, _TINYDIR_DRIVE_MAX,
dir_name_buf, _TINYDIR_FILENAME_MAX,
file_name_buf, _TINYDIR_FILENAME_MAX,
ext_buf, _TINYDIR_FILENAME_MAX);
#else
_tsplitpath(
path,
drive_buf,
dir_name_buf,
file_name_buf,
ext_buf);
#endif
if (errno)
{
return -1;
}
/* _splitpath_s not work fine with only filename and widechar support */
#ifdef _UNICODE
if (drive_buf[0] == L'\xFEFE')
drive_buf[0] = '\0';
if (dir_name_buf[0] == L'\xFEFE')
dir_name_buf[0] = '\0';
#endif
/* Emulate the behavior of dirname by returning "." for dir name if it's
empty */
if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
{
_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
}
/* Concatenate the drive letter and dir name to form full dir name */
_tinydir_strcat(drive_buf, dir_name_buf);
dir_name = drive_buf;
/* Concatenate the file name and extension to form base name */
_tinydir_strcat(file_name_buf, ext_buf);
base_name = file_name_buf;
#else
_tinydir_strcpy(dir_name_buf, path);
dir_name = dirname(dir_name_buf);
_tinydir_strcpy(file_name_buf, path);
base_name = basename(file_name_buf);
#endif
/* Special case: if the path is a root dir, open the parent dir as the file */
#if (defined _MSC_VER || defined __MINGW32__)
if (_tinydir_strlen(base_name) == 0)
#else
if ((_tinydir_strcmp(base_name, TINYDIR_STRING("/"))) == 0)
#endif
{
memset(file, 0, sizeof * file);
file->is_dir = 1;
file->is_reg = 0;
_tinydir_strcpy(file->path, dir_name);
file->extension = file->path + _tinydir_strlen(file->path);
return 0;
}
/* Open the parent directory */
if (tinydir_open(&dir, dir_name) == -1)
{
return -1;
}
/* Read through the parent directory and look for the file */
while (dir.has_next)
{
if (tinydir_readfile(&dir, file) == -1)
{
result = -1;
goto bail;
}
if (_tinydir_strcmp(file->name, base_name) == 0)
{
/* File found */
found = 1;
break;
}
tinydir_next(&dir);
}
if (!found)
{
result = -1;
errno = ENOENT;
}
bail:
tinydir_close(&dir);
return result;
}
_TINYDIR_FUNC
void _tinydir_get_ext(tinydir_file *file)
{
_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
if (period == NULL)
{
file->extension = &(file->name[_tinydir_strlen(file->name)]);
}
else
{
file->extension = period + 1;
}
}
_TINYDIR_FUNC
int _tinydir_file_cmp(const void *a, const void *b)
{
const tinydir_file *fa = (const tinydir_file *)a;
const tinydir_file *fb = (const tinydir_file *)b;
if (fa->is_dir != fb->is_dir)
{
return -(fa->is_dir - fb->is_dir);
}
return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
}
#ifndef _MSC_VER
#ifndef _TINYDIR_USE_READDIR
/*
The following authored by Ben Hutchings <ben@decadent.org.uk>
from https://womble.decadent.org.uk/readdir_r-advisory.html
*/
/* Calculate the required buffer size (in bytes) for directory *
* entries read from the given directory handle. Return -1 if this *
* this cannot be done. *
* *
* This code does not trust values of NAME_MAX that are less than *
* 255, since some systems (including at least HP-UX) incorrectly *
* define it to be a smaller value. */
_TINYDIR_FUNC
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
{
long name_max;
size_t name_end;
/* parameter may be unused */
(void)dirp;
#if defined _TINYDIR_USE_FPATHCONF
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
if (name_max == -1)
#if defined(NAME_MAX)
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
#else
return (size_t)(-1);
#endif
#elif defined(NAME_MAX)
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
#else
#error "buffer size for readdir_r cannot be determined"
#endif
name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
return (name_end > sizeof(struct _tinydir_dirent) ?
name_end : sizeof(struct _tinydir_dirent));
}
#endif
#endif
#ifdef __cplusplus
}
#endif
# if defined (_MSC_VER)
# pragma warning(pop)
# endif
#endif

69
project/.clang-format Normal file
View File

@@ -0,0 +1,69 @@
---
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: true
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
BinPackArguments: true
BinPackParameters: false
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakStringLiterals: true
ColumnLimit: 120
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
IncludeBlocks: Preserve
IncludeCategories:
- Regex: "^<(.*)>"
Priority: 0
- Regex: ^"(.*)"
Priority: 1
- Regex: "(.*)"
Priority: 2
IncludeIsMainRegex: "(_test)?$"
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
MaxEmptyLinesToKeep: 1
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Never
UseCRLF: false
...

File diff suppressed because one or more lines are too long

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project>
<configuration id="com.st.stm32cube.ide.mcu.gnu.managedbuild.config.exe.debug.1923792012" name="Debug">
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="1439583462234250292" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
</extension>
</configuration>
<configuration id="com.st.stm32cube.ide.mcu.gnu.managedbuild.config.exe.release.2077354707" name="Release">
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="1439583462234250292" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
</extension>
</configuration>
</project>

View File

@@ -1,5 +0,0 @@
635E684B79701B039C64EA45C3F84D30=80FB35DB9B6CC80F943DFC38749575DE
66BE74F758C12D739921AEA421D593D3=0
8DF89ED150041C4CBC7CB9A9CAA90856=61120D4BCEA54A37FDB6D8A0FEEC8DD5
DC22A860405A8BF2F2C095E5B6529F12=61120D4BCEA54A37FDB6D8A0FEEC8DD5
eclipse.preferences.version=1

View File

@@ -53,7 +53,9 @@ include_directories(LWIP/App LWIP/Target Core/Inc Middlewares/Third_Party/LwIP/s
add_definitions(-DDEBUG -DUSE_HAL_DRIVER -DSTM32F746xx)
file(GLOB_RECURSE SOURCES "Core/*.*" "LWIP/*.*" "Middlewares/*.*" "Drivers/*.*")
#file(GLOB_RECURSE SOURCES "Core/*.*" "LWIP/*.*" "Middlewares/*.*" "Drivers/*.*")
file(GLOB_RECURSE SOURCES "Core/Src/*.*" "Core/Startup/*.*" "LWIP/*.*" "Middlewares/*.*" "Drivers/*.*")
set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/STM32F746NGHX_FLASH.ld)

View File

@@ -52,7 +52,9 @@ include_directories(${includes})
add_definitions(${defines})
file(GLOB_RECURSE SOURCES ${sources})
#file(GLOB_RECURSE SOURCES ${sources})
file(GLOB_RECURSE SOURCES "Core/Src/*.*" "Core/Startup/*.*" "LWIP/*.*" "Middlewares/*.*" "Drivers/*.*")
set(LINKER_SCRIPT $${CMAKE_SOURCE_DIR}/${linkerScript})

61
project/Core/Inc/llfs.h Normal file
View File

@@ -0,0 +1,61 @@
/**
* @file llfs.h
* @brief Linked List Filesystem header (llfs)
* @author Lorenz C.
*/
#ifndef LLFS_H
#define LLFS_H
#include <stddef.h>
#include <stdint.h>
/**
* @brief Representation of a file in the llfs filesystem
*/
typedef struct llfs_file {
const uint8_t* data; // Pointer to the file data (len bytes)
const char* name; // Null-terminated string with the filename
size_t len; // Length of the file data
} llfs_file_t;
/**
* @brief Internal representation of a file in the filesystem
* @warning This struct should only be used in the llfs_data.c file.
*/
struct llfs_data_file {
const uint8_t* data;
const char* name;
const size_t len;
const struct llfs_data_file* next;
};
/**
* @brief Get a list of files in the filesystem
* Get a list of all the files in the filesystem.
*
* Use the filter to filter out files with a filename that do not match the filter. (e.g. "*.txt" or "*.png|*.jpg") (not
* implemented yet) Multiple filters can be used by separating them with a pipe (|).
*
* The following members of the llfs_file_t struct are set: name, len and data. @ref llfs_file_t
*
* @todo Implement file filter
*
* @param[out] file_list A pointer to an array of llfs_file_t to store the files in @ref llfs_file_t
* @param[in] max_files The maximum number of files to return (size of file_list)
* @param[in] filter A string with file extensions to filter out. (e.g. "*.txt" or "*.png|*.jpg")
* @return The number of files returned
*/
size_t llfs_file_list(llfs_file_t* file_list, size_t max_files, char* filter);
/**
* @brief Open a file
* Get a file from the filesystem by name.
*
* @param[in] name The name of the file to open
* @return A pointer to a llfs_file_t with the file data @ref llfs_file_t
* NULL if the file does not exist
*/
llfs_file_t* llfs_file_open(const char* name);
#endif // LLFS_H

View File

@@ -88,17 +88,17 @@
#endif
#if LOGGER_LEVEL <= 1
#define LOG_DEBUG(tag, fmt, ...) printf(LOG_COLOR_D"[Debug] (%lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
#define LOG_DEBUG(tag, fmt, ...) printf(LOG_COLOR_D"[Debug] (%lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
#else
#define LOG_DEBUG(tag, fmt, ...)
#endif
#if LOGGER_LEVEL <= 2
#define LOG_INFO(tag, fmt, ...) printf(LOG_COLOR_I"[Info] (%lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
#define LOG_INFO(tag, fmt, ...) printf(LOG_COLOR_I"[Info] (%lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
#else
#define LOG_INFO(tag, fmt, ...)
#endif
#if LOGGER_LEVEL <= 3
#define LOG_WARN(tag, fmt, ...) printf(LOG_COLOR_W"[Warning] (%lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
#define LOG_WARN(tag, fmt, ...) printf(LOG_COLOR_W"[Warning] (%lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
#else
#define LOG_WARN(tag, fmt, ...)
#endif
@@ -108,7 +108,7 @@
#define LOG_CRIT(tag, fmt, ...)
#endif
#if LOGGER_LEVEL <= 4
#define LOG_FATAL(tag, fmt, ...) printf(LOG_COLOR_F"[Fatal] (%lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
#define LOG_FATAL(tag, fmt, ...) printf(LOG_COLOR_F"[Fatal] (%lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
#else
#define LOG_FATAL(tag, fmt, ...)
#endif

50
project/Core/Src/llfs.c Normal file
View File

@@ -0,0 +1,50 @@
/**
* @file llfs.c
* @brief Linked List Filesystem implementation (llfs)
* @author Lorenz C.
* @todo Implement file extension filter
*/
#include <string.h>
#define LOGGER_LEVEL_WARN
#include "llfs.h"
#include "log.h"
extern struct llfs_data_file* llfs_root;
const char* TAG = "llfs";
// TODO: Implement file extension filter
size_t llfs_file_list(llfs_file_t* file_list, size_t max_files, char* filter) {
size_t file_count = 0;
const struct llfs_data_file* file = llfs_root;
LOG_DEBUG(TAG, "Getting file list with filter: %s", filter);
while (file != NULL && file_count < max_files) {
file_list[file_count].data = file->data;
file_list[file_count].name = file->name;
file_list[file_count].len = file->len;
file_count++;
file = file->next;
}
LOG_DEBUG(TAG, "Files found: %d", file_count);
return file_count;
}
llfs_file_t* llfs_file_open(const char* name) {
const struct llfs_data_file* file = llfs_root;
LOG_DEBUG(TAG, "Opening file: %s", name);
while (file != NULL) {
if (strcmp(file->name, name) == 0) {
LOG_DEBUG(TAG, "File found: %s, size: %d", file->name, file->len);
return (llfs_file_t*)file;
}
file = file->next;
}
LOG_DEBUG(TAG, "File not found: %s", name);
return NULL;
}

3152
project/Core/Src/llfs_data.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,7 @@
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#define LOGGER_LEVEL_ALL
#include "log.h"
//#include "test_img.h"
@@ -36,7 +37,7 @@
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
static const char *TAG = "main";
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
@@ -125,6 +126,7 @@ int main(void)
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
MX_LWIP_Process();
}
/* USER CODE END 3 */
}

View File

@@ -55,6 +55,8 @@
#define NO_SYS 1
/*----- Value in opt.h for SYS_LIGHTWEIGHT_PROT: 1 -----*/
#define SYS_LIGHTWEIGHT_PROT 0
/*----- Default Value for MEM_LIBC_MALLOC: 0 ---*/
#define MEM_LIBC_MALLOC 1
/*----- Default Value for MEMP_MEM_MALLOC: 0 ---*/
#define MEMP_MEM_MALLOC 1
/*----- Value in opt.h for MEM_ALIGNMENT: 1 -----*/
@@ -97,6 +99,8 @@
#define LWIP_HTTPD_CUSTOM_FILES 1
/*----- Value in opt.h for HTTPD_USE_CUSTOM_FSDATA: 0 -----*/
#define HTTPD_USE_CUSTOM_FSDATA 1
/*----- Default Value for LWIP_TFTP: 0 ---*/
#define LWIP_TFTP 1
/*----- Value in opt.h for LWIP_STATS: 1 -----*/
#define LWIP_STATS 0
/*----- Value in opt.h for CHECKSUM_GEN_IP: 1 -----*/

View File

@@ -0,0 +1,435 @@
/**
*
* @file tftp_server.c
*
* @author Logan Gunthorpe <logang@deltatee.com>
* Dirk Ziegelmeier <dziegel@gmx.de>
*
* @brief Trivial File Transfer Protocol (RFC 1350)
*
* Copyright (c) Deltatee Enterprises Ltd. 2013
* All rights reserved.
*
*/
/*
* Redistribution and use in source and binary forms, with or without
* modification,are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Author: Logan Gunthorpe <logang@deltatee.com>
* Dirk Ziegelmeier <dziegel@gmx.de>
*
*/
/**
* @defgroup tftp TFTP server
* @ingroup apps
*
* This is simple TFTP server for the lwIP raw API.
*/
#include "lwip/apps/tftp_server.h"
#if LWIP_UDP
#include "lwip/udp.h"
#include "lwip/timeouts.h"
#include "lwip/debug.h"
#define TFTP_MAX_PAYLOAD_SIZE 512
#define TFTP_HEADER_LENGTH 4
#define TFTP_RRQ 1
#define TFTP_WRQ 2
#define TFTP_DATA 3
#define TFTP_ACK 4
#define TFTP_ERROR 5
enum tftp_error {
TFTP_ERROR_FILE_NOT_FOUND = 1,
TFTP_ERROR_ACCESS_VIOLATION = 2,
TFTP_ERROR_DISK_FULL = 3,
TFTP_ERROR_ILLEGAL_OPERATION = 4,
TFTP_ERROR_UNKNOWN_TRFR_ID = 5,
TFTP_ERROR_FILE_EXISTS = 6,
TFTP_ERROR_NO_SUCH_USER = 7
};
#include <string.h>
struct tftp_state {
const struct tftp_context *ctx;
void *handle;
struct pbuf *last_data;
struct udp_pcb *upcb;
ip_addr_t addr;
u16_t port;
int timer;
int last_pkt;
u16_t blknum;
u8_t retries;
u8_t mode_write;
};
static struct tftp_state tftp_state;
static void tftp_tmr(void *arg);
static void
close_handle(void)
{
tftp_state.port = 0;
ip_addr_set_any(0, &tftp_state.addr);
if (tftp_state.last_data != NULL) {
pbuf_free(tftp_state.last_data);
tftp_state.last_data = NULL;
}
sys_untimeout(tftp_tmr, NULL);
if (tftp_state.handle) {
tftp_state.ctx->close(tftp_state.handle);
tftp_state.handle = NULL;
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: closing\n"));
}
}
static void
send_error(const ip_addr_t *addr, u16_t port, enum tftp_error code, const char *str)
{
int str_length = strlen(str);
struct pbuf *p;
u16_t *payload;
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + str_length + 1), PBUF_RAM);
if (p == NULL) {
return;
}
payload = (u16_t *) p->payload;
payload[0] = PP_HTONS(TFTP_ERROR);
payload[1] = lwip_htons(code);
MEMCPY(&payload[2], str, str_length + 1);
udp_sendto(tftp_state.upcb, p, addr, port);
pbuf_free(p);
}
static void
send_ack(u16_t blknum)
{
struct pbuf *p;
u16_t *payload;
p = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH, PBUF_RAM);
if (p == NULL) {
return;
}
payload = (u16_t *) p->payload;
payload[0] = PP_HTONS(TFTP_ACK);
payload[1] = lwip_htons(blknum);
udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
pbuf_free(p);
}
static void
resend_data(void)
{
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, tftp_state.last_data->len, PBUF_RAM);
if (p == NULL) {
return;
}
if (pbuf_copy(p, tftp_state.last_data) != ERR_OK) {
pbuf_free(p);
return;
}
udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
pbuf_free(p);
}
static void
send_data(void)
{
u16_t *payload;
int ret;
if (tftp_state.last_data != NULL) {
pbuf_free(tftp_state.last_data);
}
tftp_state.last_data = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH + TFTP_MAX_PAYLOAD_SIZE, PBUF_RAM);
if (tftp_state.last_data == NULL) {
return;
}
payload = (u16_t *) tftp_state.last_data->payload;
payload[0] = PP_HTONS(TFTP_DATA);
payload[1] = lwip_htons(tftp_state.blknum);
ret = tftp_state.ctx->read(tftp_state.handle, &payload[2], TFTP_MAX_PAYLOAD_SIZE);
if (ret < 0) {
send_error(&tftp_state.addr, tftp_state.port, TFTP_ERROR_ACCESS_VIOLATION, "Error occured while reading the file.");
close_handle();
return;
}
pbuf_realloc(tftp_state.last_data, (u16_t)(TFTP_HEADER_LENGTH + ret));
resend_data();
}
static void
recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
u16_t *sbuf = (u16_t *) p->payload;
int opcode;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(upcb);
if (((tftp_state.port != 0) && (port != tftp_state.port)) ||
(!ip_addr_isany_val(tftp_state.addr) && !ip_addr_cmp(&tftp_state.addr, addr))) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
pbuf_free(p);
return;
}
opcode = sbuf[0];
tftp_state.last_pkt = tftp_state.timer;
tftp_state.retries = 0;
switch (opcode) {
case PP_HTONS(TFTP_RRQ): /* fall through */
case PP_HTONS(TFTP_WRQ): {
const char tftp_null = 0;
char filename[TFTP_MAX_FILENAME_LEN + 1];
char mode[TFTP_MAX_MODE_LEN + 1];
u16_t filename_end_offset;
u16_t mode_end_offset;
if (tftp_state.handle != NULL) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
break;
}
sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
/* find \0 in pbuf -> end of filename string */
filename_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), 2);
if ((u16_t)(filename_end_offset - 1) > sizeof(filename)) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Filename too long/not NULL terminated");
break;
}
pbuf_copy_partial(p, filename, filename_end_offset - 1, 2);
/* find \0 in pbuf -> end of mode string */
mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset + 1);
if ((u16_t)(mode_end_offset - filename_end_offset) > sizeof(mode)) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Mode too long/not NULL terminated");
break;
}
pbuf_copy_partial(p, mode, mode_end_offset - filename_end_offset, filename_end_offset + 1);
tftp_state.handle = tftp_state.ctx->open(filename, mode, opcode == PP_HTONS(TFTP_WRQ));
tftp_state.blknum = 1;
if (!tftp_state.handle) {
send_error(addr, port, TFTP_ERROR_FILE_NOT_FOUND, "Unable to open requested file.");
break;
}
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: %s request from ", (opcode == PP_HTONS(TFTP_WRQ)) ? "write" : "read"));
ip_addr_debug_print(TFTP_DEBUG | LWIP_DBG_STATE, addr);
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, (" for '%s' mode '%s'\n", filename, mode));
ip_addr_copy(tftp_state.addr, *addr);
tftp_state.port = port;
if (opcode == PP_HTONS(TFTP_WRQ)) {
tftp_state.mode_write = 1;
send_ack(0);
} else {
tftp_state.mode_write = 0;
send_data();
}
break;
}
case PP_HTONS(TFTP_DATA): {
int ret;
u16_t blknum;
if (tftp_state.handle == NULL) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
break;
}
if (tftp_state.mode_write != 1) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a write connection");
break;
}
blknum = lwip_ntohs(sbuf[1]);
if (blknum == tftp_state.blknum) {
pbuf_remove_header(p, TFTP_HEADER_LENGTH);
ret = tftp_state.ctx->write(tftp_state.handle, p);
if (ret < 0) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file");
close_handle();
} else {
send_ack(blknum);
}
if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) {
close_handle();
} else {
tftp_state.blknum++;
}
} else if ((u16_t)(blknum + 1) == tftp_state.blknum) {
/* retransmit of previous block, ack again (casting to u16_t to care for overflow) */
send_ack(blknum);
} else {
send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number");
}
break;
}
case PP_HTONS(TFTP_ACK): {
u16_t blknum;
int lastpkt;
if (tftp_state.handle == NULL) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
break;
}
if (tftp_state.mode_write != 0) {
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a read connection");
break;
}
blknum = lwip_ntohs(sbuf[1]);
if (blknum != tftp_state.blknum) {
send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number");
break;
}
lastpkt = 0;
if (tftp_state.last_data != NULL) {
lastpkt = tftp_state.last_data->tot_len != (TFTP_MAX_PAYLOAD_SIZE + TFTP_HEADER_LENGTH);
}
if (!lastpkt) {
tftp_state.blknum++;
send_data();
} else {
close_handle();
}
break;
}
default:
send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation");
break;
}
pbuf_free(p);
}
static void
tftp_tmr(void *arg)
{
LWIP_UNUSED_ARG(arg);
tftp_state.timer++;
if (tftp_state.handle == NULL) {
return;
}
sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
if ((tftp_state.timer - tftp_state.last_pkt) > (TFTP_TIMEOUT_MSECS / TFTP_TIMER_MSECS)) {
if ((tftp_state.last_data != NULL) && (tftp_state.retries < TFTP_MAX_RETRIES)) {
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout, retrying\n"));
resend_data();
tftp_state.retries++;
} else {
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout\n"));
close_handle();
}
}
}
/** @ingroup tftp
* Initialize TFTP server.
* @param ctx TFTP callback struct
*/
err_t
tftp_init(const struct tftp_context *ctx)
{
err_t ret;
/* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
struct udp_pcb *pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
if (pcb == NULL) {
return ERR_MEM;
}
ret = udp_bind(pcb, IP_ANY_TYPE, TFTP_PORT);
if (ret != ERR_OK) {
udp_remove(pcb);
return ret;
}
tftp_state.handle = NULL;
tftp_state.port = 0;
tftp_state.ctx = ctx;
tftp_state.timer = 0;
tftp_state.last_data = NULL;
tftp_state.upcb = pcb;
udp_recv(pcb, recv, NULL);
return ERR_OK;
}
/** @ingroup tftp
* Deinitialize ("turn off") TFTP server.
*/
void tftp_cleanup(void)
{
LWIP_ASSERT("Cleanup called on non-initialized TFTP", tftp_state.upcb != NULL);
udp_remove(tftp_state.upcb);
close_handle();
memset(&tftp_state, 0, sizeof(tftp_state));
}
#endif /* LWIP_UDP */

View File

@@ -33,7 +33,7 @@ LTDC.WindowX1_L1=480
LTDC.WindowY1_L0=272
LTDC.WindowY1_L1=272
LWIP.BSP.number=1
LWIP.IPParameters=LWIP_DHCP,IP_ADDRESS,NETMASK_ADDRESS,LWIP_HTTPD,LWIP_HTTPD_CUSTOM_FILES,LWIP_HTTPD_CGI_SSI,LWIP_HTTPD_SSI,LWIP_HTTPD_SSI_RAW,LWIP_DNS,MEMP_MEM_MALLOC,LWIP_IGMP,LWIP_HTTPD_CGI,LWIP_HTTPD_SUPPORT_POST
LWIP.IPParameters=LWIP_DHCP,IP_ADDRESS,NETMASK_ADDRESS,LWIP_HTTPD,LWIP_HTTPD_CUSTOM_FILES,LWIP_HTTPD_CGI_SSI,LWIP_HTTPD_SSI,LWIP_HTTPD_SSI_RAW,LWIP_DNS,MEMP_MEM_MALLOC,LWIP_IGMP,LWIP_HTTPD_CGI,LWIP_HTTPD_SUPPORT_POST,MEM_LIBC_MALLOC,LWIP_TFTP
LWIP.IP_ADDRESS=192.168.069.010
LWIP.LWIP_DHCP=0
LWIP.LWIP_DNS=1
@@ -45,7 +45,9 @@ LWIP.LWIP_HTTPD_SSI=1
LWIP.LWIP_HTTPD_SSI_RAW=1
LWIP.LWIP_HTTPD_SUPPORT_POST=1
LWIP.LWIP_IGMP=1
LWIP.LWIP_TFTP=1
LWIP.MEMP_MEM_MALLOC=1
LWIP.MEM_LIBC_MALLOC=1
LWIP.NETMASK_ADDRESS=255.255.255.000
LWIP.Version=v2.1.2_Cube
LWIP0.BSP.STBoard=false