Merge branch 'main' into MQTT
This commit is contained in:
12
.gitignore
vendored
12
.gitignore
vendored
@@ -32,3 +32,15 @@
|
|||||||
*.app
|
*.app
|
||||||
|
|
||||||
project/Debug/
|
project/Debug/
|
||||||
|
|
||||||
|
project/.idea/
|
||||||
|
|
||||||
|
project/cmake-build-debug/
|
||||||
|
|
||||||
|
project/.settings/
|
||||||
|
|
||||||
|
project/.mxproject
|
||||||
|
|
||||||
|
project/project.launch
|
||||||
|
|
||||||
|
project/.cproject
|
||||||
150
README.md
150
README.md
@@ -1,21 +1,29 @@
|
|||||||
# 2023-Webservices_And_Applications
|
# 2023 — Webservices and Applications
|
||||||
## Used Libs, compiler and apps
|
## Table of Contents
|
||||||
|
- [Table of Contents](#table-of-contents)
|
||||||
- lwip version 2.1.2
|
- [Used Libs, compiler and apps](#used-libs-compiler-and-apps)
|
||||||
- CubeIDE version 1.12.1
|
- [Tasks](#tasks)
|
||||||
- STM32CubeMX version 6.8.1
|
- [Style Guide](#style-guide)
|
||||||
- Firmware Lib (stm32f7) 1.17.1
|
- [Editor Configuration](#editor-configuration)
|
||||||
|
- [Commit Messages Conventions](#commit-messages-conventions)
|
||||||
|
- [Documentation](#documentation)
|
||||||
|
|
||||||
## Tasks
|
## Used Libs, Compiler and Apps
|
||||||
Make for each task a sperate c and h file. The name of the file is the name of the task.
|
- lwip version 2.1.2
|
||||||
This way we can keep the code clean.
|
- CubeIDE version 1.12.1
|
||||||
|
- STM32CubeMX version 6.8.1
|
||||||
[tasks_and_taskowners.md](tasks_and_taskowners.md)
|
- 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
|
## 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
|
### Editor Configuration
|
||||||
|
|
||||||
@@ -30,106 +38,26 @@ You can choose from the following options:
|
|||||||
- For Eclipse-based editors, including STM32CubeIDE.
|
- For Eclipse-based editors, including STM32CubeIDE.
|
||||||
- You can import it within eclipse settings, `Preferences -> LANGUAGE -> Code Style -> Formatter` tab.
|
- You can import it within eclipse settings, `Preferences -> LANGUAGE -> Code Style -> Formatter` tab.
|
||||||
|
|
||||||
## Logging and Debugging Messages
|
## Commit Messages Conventions
|
||||||
The logging system is designed to make log messages clearer and improve their uniformity across the project.
|
The subject line of a commit message should follow the following rules:
|
||||||
It makes it easier to see where a log message comes from and what its verbosity is.
|
- 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:
|
Example:
|
||||||
```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.
|
Implement access right management
|
||||||
|
|
||||||
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
|
The body of a commit message may be used to explain the what and why of a commit.
|
||||||
// Info and higher priority messages will be printed
|
|
||||||
#define LOGGER_LEVEL_INFO
|
|
||||||
#include "log.h"
|
|
||||||
```
|
|
||||||
|
|
||||||
```c
|
## Documentation
|
||||||
// Only warnings and errors will be printed
|
Documentation is placed in the [docs](docs) folder.
|
||||||
#define LOGGER_LEVEL_WARN
|
If your part needs documentation (e.g. how to use tcp cmd interface), add a markdown file in the above-mentioned folder.
|
||||||
#include "log.h"
|
|
||||||
```
|
|
||||||
|
|
||||||
```c
|
This folder contains the following documents:
|
||||||
// Only log messages with level ERROR will be printed
|
- [llfs.md](docs/llfs.md): Linked List File System
|
||||||
#define LOGGER_LEVEL_CRITICAL
|
- [logger.md](docs/logger.md): Logging and Debugging Messages
|
||||||
#include "log.h"
|
- [mkllfs.md](docs/mkllfs.md): Make Linked List File System
|
||||||
```
|
- [style_guide.md](docs/style_guide.md): Style Guide
|
||||||
|
|
||||||
```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
|
|
||||||
```
|
|
||||||
57
docs/llfs.md
Normal file
57
docs/llfs.md
Normal 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
103
docs/logger.md
Normal 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
33
docs/mkllfs.md
Normal 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
2
mkllfs/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
cmake-build-debug
|
||||||
|
.idea
|
||||||
6
mkllfs/CMakeLists.txt
Normal file
6
mkllfs/CMakeLists.txt
Normal 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
187
mkllfs/main.c
Normal 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
838
mkllfs/tinydir.h
Normal 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
69
project/.clang-format
Normal 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
@@ -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="1598175355152594562" 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 "${INPUTS}"" 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="1598175355152594562" 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 "${INPUTS}"" prefer-non-shared="true">
|
|
||||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
|
||||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
|
||||||
</provider>
|
|
||||||
</extension>
|
|
||||||
</configuration>
|
|
||||||
</project>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
635E684B79701B039C64EA45C3F84D30=80FB35DB9B6CC80F943DFC38749575DE
|
|
||||||
66BE74F758C12D739921AEA421D593D3=0
|
|
||||||
DC22A860405A8BF2F2C095E5B6529F12=61120D4BCEA54A37FDB6D8A0FEEC8DD5
|
|
||||||
eclipse.preferences.version=1
|
|
||||||
75
project/CMakeLists.txt
Normal file
75
project/CMakeLists.txt
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#THIS FILE IS AUTO GENERATED FROM THE TEMPLATE! DO NOT CHANGE!
|
||||||
|
set(CMAKE_SYSTEM_NAME Generic)
|
||||||
|
set(CMAKE_SYSTEM_VERSION 1)
|
||||||
|
cmake_minimum_required(VERSION 3.26)
|
||||||
|
|
||||||
|
# specify cross-compilers and tools
|
||||||
|
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
|
||||||
|
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
|
||||||
|
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
|
||||||
|
set(CMAKE_AR arm-none-eabi-ar)
|
||||||
|
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
|
||||||
|
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
|
||||||
|
set(SIZE arm-none-eabi-size)
|
||||||
|
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||||
|
|
||||||
|
# project settings
|
||||||
|
project(project C CXX ASM)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
|
||||||
|
#Uncomment for hardware floating point
|
||||||
|
#add_compile_definitions(ARM_MATH_CM4;ARM_MATH_MATRIX_CHECK;ARM_MATH_ROUNDING)
|
||||||
|
#add_compile_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
|
||||||
|
#add_link_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
|
||||||
|
|
||||||
|
#Uncomment for software floating point
|
||||||
|
#add_compile_options(-mfloat-abi=soft)
|
||||||
|
|
||||||
|
add_compile_options(-mcpu=cortex-m7 -mthumb -mthumb-interwork)
|
||||||
|
add_compile_options(-ffunction-sections -fdata-sections -fno-common -fmessage-length=0)
|
||||||
|
|
||||||
|
# uncomment to mitigate c++17 absolute addresses warnings
|
||||||
|
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-register")
|
||||||
|
|
||||||
|
# Enable assembler files preprocessing
|
||||||
|
add_compile_options($<$<COMPILE_LANGUAGE:ASM>:-x$<SEMICOLON>assembler-with-cpp>)
|
||||||
|
|
||||||
|
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
|
||||||
|
message(STATUS "Maximum optimization for speed")
|
||||||
|
add_compile_options(-Ofast)
|
||||||
|
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
|
||||||
|
message(STATUS "Maximum optimization for speed, debug info included")
|
||||||
|
add_compile_options(-Ofast -g)
|
||||||
|
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")
|
||||||
|
message(STATUS "Maximum optimization for size")
|
||||||
|
add_compile_options(-Os)
|
||||||
|
else ()
|
||||||
|
message(STATUS "Minimal optimization, debug info included")
|
||||||
|
add_compile_options(-Og -g)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
include_directories(LWIP/App LWIP/Target Core/Inc Middlewares/Third_Party/LwIP/src/include Middlewares/Third_Party/LwIP/system Drivers/STM32F7xx_HAL_Driver/Inc Drivers/STM32F7xx_HAL_Driver/Inc/Legacy Drivers/BSP/Components/lan8742 Middlewares/Third_Party/LwIP/src/include/netif/ppp Middlewares/Third_Party/LwIP/src/apps/http Drivers/CMSIS/Device/ST/STM32F7xx/Include Middlewares/Third_Party/LwIP/src/include/lwip Middlewares/Third_Party/LwIP/src/include/lwip/apps Middlewares/Third_Party/LwIP/src/include/lwip/priv Middlewares/Third_Party/LwIP/src/include/lwip/prot Middlewares/Third_Party/LwIP/src/include/netif Middlewares/Third_Party/LwIP/src/include/compat/posix Middlewares/Third_Party/LwIP/src/include/compat/posix/arpa Middlewares/Third_Party/LwIP/src/include/compat/posix/net Middlewares/Third_Party/LwIP/src/include/compat/posix/sys Middlewares/Third_Party/LwIP/src/include/compat/stdc Middlewares/Third_Party/LwIP/system/arch Drivers/CMSIS/Include)
|
||||||
|
|
||||||
|
add_definitions(-DDEBUG -DUSE_HAL_DRIVER -DSTM32F746xx)
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
add_link_options(-Wl,-gc-sections,--print-memory-usage,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map)
|
||||||
|
add_link_options(-mcpu=cortex-m7 -mthumb -mthumb-interwork)
|
||||||
|
add_link_options(-T ${LINKER_SCRIPT})
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME}.elf ${SOURCES} ${LINKER_SCRIPT})
|
||||||
|
|
||||||
|
set(HEX_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.hex)
|
||||||
|
set(BIN_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.bin)
|
||||||
|
|
||||||
|
add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
|
||||||
|
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${PROJECT_NAME}.elf> ${HEX_FILE}
|
||||||
|
COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${PROJECT_NAME}.elf> ${BIN_FILE}
|
||||||
|
COMMENT "Building ${HEX_FILE}
|
||||||
|
Building ${BIN_FILE}")
|
||||||
74
project/CMakeLists_template.txt
Normal file
74
project/CMakeLists_template.txt
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#${templateWarning}
|
||||||
|
set(CMAKE_SYSTEM_NAME Generic)
|
||||||
|
set(CMAKE_SYSTEM_VERSION 1)
|
||||||
|
${cmakeRequiredVersion}
|
||||||
|
# specify cross-compilers and tools
|
||||||
|
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
|
||||||
|
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
|
||||||
|
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
|
||||||
|
set(CMAKE_AR arm-none-eabi-ar)
|
||||||
|
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
|
||||||
|
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
|
||||||
|
set(SIZE arm-none-eabi-size)
|
||||||
|
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||||
|
|
||||||
|
# project settings
|
||||||
|
project(${projectName} C CXX ASM)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
|
||||||
|
#Uncomment for hardware floating point
|
||||||
|
#add_compile_definitions(ARM_MATH_CM4;ARM_MATH_MATRIX_CHECK;ARM_MATH_ROUNDING)
|
||||||
|
#add_compile_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
|
||||||
|
#add_link_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
|
||||||
|
|
||||||
|
#Uncomment for software floating point
|
||||||
|
#add_compile_options(-mfloat-abi=soft)
|
||||||
|
|
||||||
|
add_compile_options(-mcpu=${mcpu} -mthumb -mthumb-interwork)
|
||||||
|
add_compile_options(-ffunction-sections -fdata-sections -fno-common -fmessage-length=0)
|
||||||
|
|
||||||
|
# uncomment to mitigate c++17 absolute addresses warnings
|
||||||
|
#set(CMAKE_CXX_FLAGS "$${CMAKE_CXX_FLAGS} -Wno-register")
|
||||||
|
|
||||||
|
# Enable assembler files preprocessing
|
||||||
|
add_compile_options($<$<COMPILE_LANGUAGE:ASM>:-x$<SEMICOLON>assembler-with-cpp>)
|
||||||
|
|
||||||
|
if ("$${CMAKE_BUILD_TYPE}" STREQUAL "Release")
|
||||||
|
message(STATUS "Maximum optimization for speed")
|
||||||
|
add_compile_options(-Ofast)
|
||||||
|
elseif ("$${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
|
||||||
|
message(STATUS "Maximum optimization for speed, debug info included")
|
||||||
|
add_compile_options(-Ofast -g)
|
||||||
|
elseif ("$${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")
|
||||||
|
message(STATUS "Maximum optimization for size")
|
||||||
|
add_compile_options(-Os)
|
||||||
|
else ()
|
||||||
|
message(STATUS "Minimal optimization, debug info included")
|
||||||
|
add_compile_options(-Og -g)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
include_directories(${includes})
|
||||||
|
|
||||||
|
add_definitions(${defines})
|
||||||
|
|
||||||
|
#file(GLOB_RECURSE SOURCES ${sources})
|
||||||
|
file(GLOB_RECURSE SOURCES "Core/Src/*.*" "Core/Startup/*.*" "LWIP/*.*" "Middlewares/*.*" "Drivers/*.*")
|
||||||
|
|
||||||
|
|
||||||
|
set(LINKER_SCRIPT $${CMAKE_SOURCE_DIR}/${linkerScript})
|
||||||
|
|
||||||
|
add_link_options(-Wl,-gc-sections,--print-memory-usage,-Map=$${PROJECT_BINARY_DIR}/$${PROJECT_NAME}.map)
|
||||||
|
add_link_options(-mcpu=${mcpu} -mthumb -mthumb-interwork)
|
||||||
|
add_link_options(-T $${LINKER_SCRIPT})
|
||||||
|
|
||||||
|
add_executable($${PROJECT_NAME}.elf $${SOURCES} $${LINKER_SCRIPT})
|
||||||
|
|
||||||
|
set(HEX_FILE $${PROJECT_BINARY_DIR}/$${PROJECT_NAME}.hex)
|
||||||
|
set(BIN_FILE $${PROJECT_BINARY_DIR}/$${PROJECT_NAME}.bin)
|
||||||
|
|
||||||
|
add_custom_command(TARGET $${PROJECT_NAME}.elf POST_BUILD
|
||||||
|
COMMAND $${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:$${PROJECT_NAME}.elf> $${HEX_FILE}
|
||||||
|
COMMAND $${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:$${PROJECT_NAME}.elf> $${BIN_FILE}
|
||||||
|
COMMENT "Building $${HEX_FILE}
|
||||||
|
Building $${BIN_FILE}")
|
||||||
61
project/Core/Inc/llfs.h
Normal file
61
project/Core/Inc/llfs.h
Normal 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
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @file log.h
|
* @file log.h
|
||||||
* @brief Logger header
|
* @brief Logger header
|
||||||
* @author Lorenz C.
|
* @authors Lorenz C. Speetjens S.
|
||||||
*
|
*
|
||||||
* This logging library provides a simple logging interface with different verbosity levels.
|
* This logging library provides a simple logging interface with different verbosity levels.
|
||||||
* Each tag can have its own log level.
|
* Each tag can have its own log level.
|
||||||
@@ -88,27 +88,27 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LOGGER_LEVEL <= 1
|
#if LOGGER_LEVEL <= 1
|
||||||
#define LOG_DEBUG(tag, fmt, ...) printf(LOG_COLOR_D"[Debug] (%lu) [%s]: " fmt LOG_RESET_COLOR, 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
|
#else
|
||||||
#define LOG_DEBUG(tag, fmt, ...)
|
#define LOG_DEBUG(tag, fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
#if LOGGER_LEVEL <= 2
|
#if LOGGER_LEVEL <= 2
|
||||||
#define LOG_INFO(tag, fmt, ...) printf(LOG_COLOR_I"[Info] (%lu) [%s]: " fmt LOG_RESET_COLOR, 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
|
#else
|
||||||
#define LOG_INFO(tag, fmt, ...)
|
#define LOG_INFO(tag, fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
#if LOGGER_LEVEL <= 3
|
#if LOGGER_LEVEL <= 3
|
||||||
#define LOG_WARN(tag, fmt, ...) printf(LOG_COLOR_W"[Warning] (%lu) [%s]: " fmt LOG_RESET_COLOR, 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
|
#else
|
||||||
#define LOG_WARN(tag, fmt, ...)
|
#define LOG_WARN(tag, fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
#if LOGGER_LEVEL <= 4
|
#if LOGGER_LEVEL <= 4
|
||||||
#define LOG_CRIT(tag, fmt, ...) printf(LOG_COLOR_C"[Critical] (%lu) [%s]: " fmt LOG_RESET_COLOR, logger_get_timestamp(), tag, ##__VA_ARGS__)
|
#define LOG_CRIT(tag, fmt, ...) printf(LOG_COLOR_C"[Critical] (%lu) [%s]: " fmt LOG_RESET_COLOR "\r\n", logger_get_timestamp(), tag, ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_CRIT(tag, fmt, ...)
|
#define LOG_CRIT(tag, fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
#if LOGGER_LEVEL <= 4
|
#if LOGGER_LEVEL <= 4
|
||||||
#define LOG_FATAL(tag, fmt, ...) printf(LOG_COLOR_F"[Fatal] (%lu) [%s]: " fmt LOG_RESET_COLOR, 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
|
#else
|
||||||
#define LOG_FATAL(tag, fmt, ...)
|
#define LOG_FATAL(tag, fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
50
project/Core/Src/llfs.c
Normal file
50
project/Core/Src/llfs.c
Normal 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
3152
project/Core/Src/llfs_data.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @file log.c
|
* @file log.c
|
||||||
* @brief Logger implementation
|
* @brief Logger implementation
|
||||||
* @author Lorenz C. && Speetjens S.
|
* @authors Lorenz C. && Speetjens S.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
/* Private includes ----------------------------------------------------------*/
|
/* Private includes ----------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN Includes */
|
/* USER CODE BEGIN Includes */
|
||||||
|
#define LOGGER_LEVEL_ALL
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
/* USER CODE END Includes */
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@
|
|||||||
|
|
||||||
/* Private define ------------------------------------------------------------*/
|
/* Private define ------------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN PD */
|
/* USER CODE BEGIN PD */
|
||||||
|
static const char *TAG = "main";
|
||||||
/* USER CODE END PD */
|
/* USER CODE END PD */
|
||||||
|
|
||||||
/* Private macro -------------------------------------------------------------*/
|
/* Private macro -------------------------------------------------------------*/
|
||||||
@@ -118,6 +119,7 @@ int main(void)
|
|||||||
/* USER CODE END WHILE */
|
/* USER CODE END WHILE */
|
||||||
|
|
||||||
/* USER CODE BEGIN 3 */
|
/* USER CODE BEGIN 3 */
|
||||||
|
MX_LWIP_Process();
|
||||||
}
|
}
|
||||||
/* USER CODE END 3 */
|
/* USER CODE END 3 */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,8 @@
|
|||||||
#define NO_SYS 1
|
#define NO_SYS 1
|
||||||
/*----- Value in opt.h for SYS_LIGHTWEIGHT_PROT: 1 -----*/
|
/*----- Value in opt.h for SYS_LIGHTWEIGHT_PROT: 1 -----*/
|
||||||
#define SYS_LIGHTWEIGHT_PROT 0
|
#define SYS_LIGHTWEIGHT_PROT 0
|
||||||
|
/*----- Default Value for MEM_LIBC_MALLOC: 0 ---*/
|
||||||
|
#define MEM_LIBC_MALLOC 1
|
||||||
/*----- Default Value for MEMP_MEM_MALLOC: 0 ---*/
|
/*----- Default Value for MEMP_MEM_MALLOC: 0 ---*/
|
||||||
#define MEMP_MEM_MALLOC 1
|
#define MEMP_MEM_MALLOC 1
|
||||||
/*----- Value in opt.h for MEM_ALIGNMENT: 1 -----*/
|
/*----- Value in opt.h for MEM_ALIGNMENT: 1 -----*/
|
||||||
@@ -97,6 +99,8 @@
|
|||||||
#define LWIP_HTTPD_CUSTOM_FILES 1
|
#define LWIP_HTTPD_CUSTOM_FILES 1
|
||||||
/*----- Value in opt.h for HTTPD_USE_CUSTOM_FSDATA: 0 -----*/
|
/*----- Value in opt.h for HTTPD_USE_CUSTOM_FSDATA: 0 -----*/
|
||||||
#define HTTPD_USE_CUSTOM_FSDATA 1
|
#define HTTPD_USE_CUSTOM_FSDATA 1
|
||||||
|
/*----- Default Value for LWIP_TFTP: 0 ---*/
|
||||||
|
#define LWIP_TFTP 1
|
||||||
/*----- Value in opt.h for LWIP_STATS: 1 -----*/
|
/*----- Value in opt.h for LWIP_STATS: 1 -----*/
|
||||||
#define LWIP_STATS 0
|
#define LWIP_STATS 0
|
||||||
/*----- Value in opt.h for CHECKSUM_GEN_IP: 1 -----*/
|
/*----- Value in opt.h for CHECKSUM_GEN_IP: 1 -----*/
|
||||||
|
|||||||
435
project/Middlewares/Third_Party/LwIP/src/apps/tftp/tftp_server.c
vendored
Normal file
435
project/Middlewares/Third_Party/LwIP/src/apps/tftp/tftp_server.c
vendored
Normal 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 */
|
||||||
@@ -33,7 +33,7 @@ LTDC.WindowX1_L1=480
|
|||||||
LTDC.WindowY1_L0=272
|
LTDC.WindowY1_L0=272
|
||||||
LTDC.WindowY1_L1=272
|
LTDC.WindowY1_L1=272
|
||||||
LWIP.BSP.number=1
|
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.IP_ADDRESS=192.168.069.010
|
||||||
LWIP.LWIP_DHCP=0
|
LWIP.LWIP_DHCP=0
|
||||||
LWIP.LWIP_DNS=1
|
LWIP.LWIP_DNS=1
|
||||||
@@ -45,7 +45,9 @@ LWIP.LWIP_HTTPD_SSI=1
|
|||||||
LWIP.LWIP_HTTPD_SSI_RAW=1
|
LWIP.LWIP_HTTPD_SSI_RAW=1
|
||||||
LWIP.LWIP_HTTPD_SUPPORT_POST=1
|
LWIP.LWIP_HTTPD_SUPPORT_POST=1
|
||||||
LWIP.LWIP_IGMP=1
|
LWIP.LWIP_IGMP=1
|
||||||
|
LWIP.LWIP_TFTP=1
|
||||||
LWIP.MEMP_MEM_MALLOC=1
|
LWIP.MEMP_MEM_MALLOC=1
|
||||||
|
LWIP.MEM_LIBC_MALLOC=1
|
||||||
LWIP.NETMASK_ADDRESS=255.255.255.000
|
LWIP.NETMASK_ADDRESS=255.255.255.000
|
||||||
LWIP.Version=v2.1.2_Cube
|
LWIP.Version=v2.1.2_Cube
|
||||||
LWIP0.BSP.STBoard=false
|
LWIP0.BSP.STBoard=false
|
||||||
|
|||||||
Reference in New Issue
Block a user