Merge branch 'main' into Modbus_TCP_Obe
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -59,3 +59,4 @@ project/Scripts
|
||||
Scripts/
|
||||
|
||||
project/project\ Debug.launch
|
||||
build/
|
||||
22
CMakeLists.txt
Normal file
22
CMakeLists.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||
|
||||
project(WSAA_tests LANGUAGES CXX C)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(VERSION_MAJOR 1)
|
||||
set(VERSION_MINOR 0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
|
||||
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
|
||||
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
|
||||
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
|
||||
set(PROJECT_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
@@ -6,6 +6,7 @@
|
||||
- [Style Guide](#style-guide)
|
||||
- [Editor Configuration](#editor-configuration)
|
||||
- [Commit Messages Conventions](#commit-messages-conventions)
|
||||
- [Writing File System Data to QSPI Flash](#writing-file-system-data-to-qspi-flash)
|
||||
- [Documentation](#documentation)
|
||||
|
||||
## Used Libs, Compiler and Apps
|
||||
@@ -52,6 +53,10 @@ Implement access right management
|
||||
|
||||
The body of a commit message may be used to explain the what and why of a commit.
|
||||
|
||||
## Writing File System Data to QSPI Flash
|
||||
Please read the [llfs.md](./docs/llfs.md#enabling-the-external-loader-in-stm32cubeide) document for instructions
|
||||
on how to enable the external loader in STM32CubeIDE.
|
||||
|
||||
## 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.
|
||||
@@ -62,3 +67,4 @@ This folder contains the following documents:
|
||||
- [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
|
||||
- [tftp.md](docs/tftp.md): Trivial File Transfer Protocol
|
||||
BIN
docs/img/ext_loader_step_1.png
Normal file
BIN
docs/img/ext_loader_step_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
docs/img/ext_loader_step_2.png
Normal file
BIN
docs/img/ext_loader_step_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
@@ -104,7 +104,7 @@ void main(void) {
|
||||
#### Drawing text on the screen
|
||||
|
||||
```c
|
||||
void lcd_display_text(const char* text, uint16_t x_pos, uint16_t y_pos, uint32_t color, uint32_t bg_color, sFONT *font);
|
||||
void lcd_display_text(const char* text, uint16_t x_pos, uint16_t y_pos, uint32_t color, sFONT *font);
|
||||
```
|
||||
|
||||
```c
|
||||
@@ -116,7 +116,7 @@ void main(void) {
|
||||
...
|
||||
lcd_init(true);
|
||||
...
|
||||
lcd_display_text("This is a text string.", 10, 10, LCD_GREEN, LCD_BLACK, LCD_FONT16);
|
||||
lcd_display_text("This is a text string.", 10, 10, LCD_GREEN, LCD_FONT16);
|
||||
}
|
||||
```
|
||||
Display text on the LCD screen in a certain color. When text width exceeds BSP_LCD_GetXSize(), a text wrap will be performed. If the text wrap is between two will be injected.
|
||||
@@ -194,13 +194,13 @@ void main(void) {
|
||||
...
|
||||
lcd_init(true);
|
||||
...
|
||||
|
||||
|
||||
// From a C-array
|
||||
lcd_gif_t* gif = lcd_draw_gif(gif_array, gif_size, 0, 0);
|
||||
|
||||
|
||||
// From the filesystem
|
||||
lcd_gif_t* gif = lcd_draw_gif_from_fs("st.gif", 0, 0);
|
||||
|
||||
|
||||
if (gif == NULL) {
|
||||
LOG_WARNING("GIF could not be drawn");
|
||||
}
|
||||
@@ -229,15 +229,22 @@ Call this function before drawing over the GIF.
|
||||
This function should not be called on a GIF that has already been stopped (GIFs with a loop count will stop automatically).
|
||||
It is possible that the handler has been assigned to a new GIF, so it would stop the new GIF instead.
|
||||
|
||||
#### Stopping all GIF animations
|
||||
```c
|
||||
void lcd_stop_all_gifs(void);
|
||||
```
|
||||
This function stops all the GIF animations and frees the memory allocated for the GIF.
|
||||
Call this function before drawing over the GIF.
|
||||
|
||||
#### Checking if a GIF is still running
|
||||
```c
|
||||
bool lcd_gif_is_playing(lcd_gif_t* gif);
|
||||
```
|
||||
NOTE: It is possible that the GIF has stopped playing, but another GIF has taken its slot and is still playing.
|
||||
|
||||
#### Clearing the LCD screen
|
||||
#### Clearing the text on the LCD screen
|
||||
```c
|
||||
void lcd_clear(uint32_t color);
|
||||
void lcd_clear_text(void);
|
||||
```
|
||||
|
||||
```c
|
||||
@@ -246,9 +253,29 @@ void lcd_clear(uint32_t color);
|
||||
void main(void) {
|
||||
...
|
||||
lcd_init(true);
|
||||
lcd_display_text("Hello world!", 0, 0, LCD_GREEN, LCD_FONT20);
|
||||
...
|
||||
lcd_clear(LCD_BLACK);
|
||||
lcd_clear_text();
|
||||
}
|
||||
```
|
||||
|
||||
Clears the LCD screen to the specified color.
|
||||
Clears all text strings on the LCD screen.
|
||||
|
||||
#### Clearing the images on the LCD screen
|
||||
```c
|
||||
void lcd_clear_images(void);
|
||||
```
|
||||
|
||||
```c
|
||||
#include "lcd_api.h"
|
||||
|
||||
void main(void) {
|
||||
...
|
||||
lcd_init(true);
|
||||
lcd_draw_img_from_fs("st.bmp", 300, 100);
|
||||
...
|
||||
lcd_clear_images();
|
||||
}
|
||||
```
|
||||
|
||||
Clears all text strings on the LCD screen.
|
||||
|
||||
14
docs/llfs.md
14
docs/llfs.md
@@ -24,6 +24,7 @@ restricting operations solely to read functions.
|
||||
- [Reading a file](#reading-a-file)
|
||||
- [Getting the number of files](#getting-the-number-of-files)
|
||||
- [Using the POSIX file functions](#using-the-posix-file-functions)
|
||||
- [Enabling the external loader in STM32CubeIDE](#enabling-the-external-loader-in-stm32cubeide)
|
||||
|
||||
## Initialization
|
||||
Before using the llfs API, or the file related POSIX (fopen, fgetc, ...) functions, the filesystem must be initialized by calling `llfs_init()`.
|
||||
@@ -161,3 +162,16 @@ The following functions are tested and working, but other functions might also w
|
||||
- `rewind`
|
||||
- `fstat`
|
||||
- `fileno`
|
||||
|
||||
## Enabling the external loader in STM32CubeIDE
|
||||
In order to write the file system data to the QSPI flash, the external loader must be enabled in STM32CubeIDE.
|
||||
This can be done by opening the debug configuration:
|
||||
|
||||

|
||||
|
||||
Then, in the `Debugger` tab:
|
||||
3. Enable the `External Loader`
|
||||
4. Click the `Scan` button
|
||||
5. Select the correct loader: `N25Q128A_STM32F746G-DISCO, 0x90000000 ...`
|
||||
|
||||

|
||||
|
||||
@@ -7,7 +7,7 @@ The llfs filesystem is a flat filesystem, meaning that it does not support direc
|
||||
|
||||
The mkllfs utilit can be used to generate the `llfs_data.c` file. The `llfs_data.c` file from a directory with files.
|
||||
|
||||
A pre-compiled version can be download: [mkllfs.exe](https://github.com/Sani7/2023-Webservices_And_Applications/releases/tag/v0.2.0)
|
||||
A pre-compiled version can be download: [mkllfs.exe](https://github.com/Sani7/2023-Webservices_And_Applications/releases/tag/v0.2.1)
|
||||
|
||||
## Usage
|
||||
The mkllfs utility can be used as follows:
|
||||
|
||||
35
docs/tftp.md
Normal file
35
docs/tftp.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# TFTP
|
||||
This is the documentation of the TFTP task
|
||||
## Initialization
|
||||
The TFTP task is initialized in the main function.
|
||||
```c
|
||||
// Initialize TFTP task
|
||||
tftp_init();
|
||||
```
|
||||
## Deinitialization
|
||||
If you would ever want to deinitialize the TFTP task, you can do so by calling the following function.
|
||||
```c
|
||||
// Deinitialize TFTP task
|
||||
tftp_server_deinit();
|
||||
```
|
||||
|
||||
## Usage
|
||||
The TFTP task is used to receive and send files via TFTP.
|
||||
### Receive a file
|
||||
index.txt contains a list of files on the file system.
|
||||
```bash
|
||||
bash $ tftp <ip>
|
||||
tftp $ get index.txt
|
||||
```
|
||||
### Send a file
|
||||
You can only write to the following files:
|
||||
- virtImage.bmp
|
||||
```bash
|
||||
bash $ tftp <ip>
|
||||
tftp $ put <image.bmp> virtImage.bmp
|
||||
```
|
||||
- virtImage.gif
|
||||
```bash
|
||||
bash $ tftp <ip>
|
||||
tftp $ put <image.gif> virtImage.gif
|
||||
```
|
||||
BIN
llfs-data/disappointed.gif
Normal file
BIN
llfs-data/disappointed.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
BIN
llfs-data/dog.gif
Normal file
BIN
llfs-data/dog.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
BIN
llfs-data/monday-left-me-broken-mario.gif
Normal file
BIN
llfs-data/monday-left-me-broken-mario.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
llfs-data/patpat-pat.gif
Normal file
BIN
llfs-data/patpat-pat.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file main.c
|
||||
* @brief Converts files to a C file that can be used by llfs (linked list file system).
|
||||
* @version 0.2.0
|
||||
* @version 0.2.1
|
||||
* @author Lorenz C.
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <string.h>
|
||||
#include "tinydir.h"
|
||||
|
||||
#define VERSION "0.2.0"
|
||||
#define VERSION "0.2.1"
|
||||
#define LLFS_VERSION "0.1.1"
|
||||
#define MAX_PATH_LEN 256
|
||||
|
||||
@@ -125,7 +125,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
// 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);
|
||||
fprintf(out_file, "const struct llfs_data_file *llfs_root =%s%s;\n", (strcmp(prev_llfs_name, "NULL") == 0 ? " " : " &"), prev_llfs_name);
|
||||
|
||||
// Print the number of files
|
||||
printf("Successfully converted %d files.\r\n", file_count);
|
||||
|
||||
@@ -100,10 +100,9 @@ void lcd_task(void);
|
||||
* @param[in] x_pos X-position
|
||||
* @param[in] y_pos Y-position
|
||||
* @param[in] color Color in which the text will be displayed, see preset colors in defines above
|
||||
* @param[in] bg_color Background color for the text
|
||||
* @param[in] font Font size, see defines above in file
|
||||
*/
|
||||
void lcd_display_text(uint8_t* text, uint16_t x_pos, uint16_t y_pos, uint32_t color, uint32_t bg_color, sFONT *font);
|
||||
void lcd_display_text(const char* text, uint16_t x_pos, uint16_t y_pos, uint32_t color, sFONT *font);
|
||||
|
||||
/**
|
||||
* @brief Draw BMP image on screen
|
||||
@@ -144,13 +143,25 @@ void lcd_draw_bmp_img(uint8_t* bmp_buff, uint32_t x_pos, uint32_t y_pos);
|
||||
void lcd_draw_img_from_fs(const char* name, uint32_t x_pos, uint32_t y_pos);
|
||||
|
||||
/**
|
||||
* @brief Clear LCD screen
|
||||
* Clears the whole LCD screen to the desired color
|
||||
* @brief Clear LCD text
|
||||
* Clears the text drawn on the LCD screen
|
||||
*
|
||||
*@param[in] color Color to which the LCD should be cleared
|
||||
*/
|
||||
void lcd_clear_text(void);
|
||||
|
||||
void lcd_clear(uint32_t color);
|
||||
/**
|
||||
* @brief Clear images
|
||||
* Clears the images drawn on the LCD screen
|
||||
*
|
||||
*/
|
||||
void lcd_clear_images(void);
|
||||
|
||||
/**
|
||||
* @brief LCD stop all GIFs
|
||||
* Stops all playing GIFs on lcd screen
|
||||
*
|
||||
*/
|
||||
void lcd_stop_all_gifs(void);
|
||||
|
||||
/**
|
||||
* @brief Draw GIF image on screen from memory
|
||||
|
||||
79
project/Core/Inc/tftp.h
Normal file
79
project/Core/Inc/tftp.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @file tftp.h
|
||||
* @brief tftp server
|
||||
* @author Sander S.
|
||||
*/
|
||||
|
||||
#ifndef PROJECT_TFTP_H
|
||||
#define PROJECT_TFTP_H
|
||||
#include <tftp_server.h>
|
||||
#ifndef TESTING
|
||||
#include "lcd_api.h"
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#define LOGGER_LEVEL_ALL
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "llfs.h"
|
||||
#include "log.h"
|
||||
|
||||
#define TFTP_READ 0
|
||||
|
||||
#ifndef UNUSED
|
||||
#define UNUSED(x) (void)(x)
|
||||
#endif
|
||||
|
||||
typedef struct tftp_custom_file_s {
|
||||
char* data;
|
||||
size_t len;
|
||||
char* name;
|
||||
size_t offset;
|
||||
} tftp_custom_file_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the TFTP server
|
||||
*/
|
||||
void tftp_server_init(void);
|
||||
|
||||
/**
|
||||
* @brief Uninitialize the TFTP server
|
||||
*/
|
||||
void tftp_server_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Custom fseek function
|
||||
*
|
||||
* @param handle The custom file handle
|
||||
* @param offset The offset
|
||||
* @param whence The whence
|
||||
*/
|
||||
void tftp_custom_fseek(tftp_custom_file_t* handle, size_t offset, int whence);
|
||||
|
||||
/**
|
||||
* @brief Custom fread function
|
||||
*
|
||||
* @param buf The buffer to read from
|
||||
* @param bytes The amount of bytes to read
|
||||
* @param handle The custom file handle
|
||||
* @return The amount of bytes read
|
||||
*/
|
||||
size_t tftp_custom_fread(void* buf, size_t bytes, tftp_custom_file_t* handle);
|
||||
|
||||
/**
|
||||
* @brief Custom fwrite function
|
||||
*
|
||||
* @param buf The buffer to write to
|
||||
* @param bytes The amount of bytes to write
|
||||
* @param handle The custom file handle
|
||||
* @return The amount of bytes written
|
||||
*/
|
||||
size_t tftp_custom_fwrite(const void* buf, size_t bytes, tftp_custom_file_t* handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // PROJECT_TFTP_H
|
||||
@@ -22,18 +22,22 @@ void lcd_init(bool bl_on) {
|
||||
|
||||
BSP_LCD_Init();
|
||||
BSP_LCD_LayerDefaultInit(1, LCD_FB_START_ADDRESS);
|
||||
BSP_LCD_LayerDefaultInit(0, LCD_FB_START_ADDRESS + (BSP_LCD_GetXSize() * BSP_LCD_GetYSize() * 4));
|
||||
BSP_LCD_LayerDefaultInit(0, LCD_FB_START_ADDRESS + (BSP_LCD_GetXSize() * BSP_LCD_GetYSize()) * 4);
|
||||
BSP_LCD_SelectLayer(0);
|
||||
BSP_LCD_Clear(LCD_COLOR_BLACK);
|
||||
BSP_LCD_Clear(0);
|
||||
BSP_LCD_SelectLayer(1);
|
||||
BSP_LCD_Clear(LCD_COLOR_BLACK);
|
||||
BSP_LCD_Clear(0);
|
||||
BSP_LCD_SetLayerVisible(0, ENABLE);
|
||||
BSP_LCD_SetLayerVisible(1, ENABLE);
|
||||
if (bl_on) {
|
||||
HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_12, GPIO_PIN_SET);
|
||||
LOG_INFO(TAG, "LCD initialise with backlight");
|
||||
return;
|
||||
}
|
||||
HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_RESET);
|
||||
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_12, GPIO_PIN_RESET);
|
||||
LOG_INFO(TAG, "LCD initialise without backlight");
|
||||
}
|
||||
|
||||
void lcd_task(void) {
|
||||
@@ -80,39 +84,42 @@ void lcd_task(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_display_text(uint8_t* text, uint16_t x_pos, uint16_t y_pos, uint32_t color, uint32_t bg_color, sFONT* font) {
|
||||
void lcd_display_text(const char* text, uint16_t x_pos, uint16_t y_pos, uint32_t color, sFONT* font) {
|
||||
BSP_LCD_SelectLayer(1);
|
||||
LOG_INFO(TAG, "Display text: %s @x=%d,y=%d", text, x_pos, y_pos);
|
||||
|
||||
uint16_t tot_length = x_pos + (strlen(text) * font->Width);
|
||||
uint16_t tot_length = x_pos + ((uint16_t)strlen(text) * font->Width);
|
||||
if ((x_pos % font->Width) != 0) {
|
||||
x_pos -= (x_pos % font->Width);
|
||||
}
|
||||
|
||||
BSP_LCD_SetTextColor(color);
|
||||
BSP_LCD_SetBackColor(bg_color);
|
||||
BSP_LCD_SetBackColor(0);
|
||||
BSP_LCD_SetFont(font);
|
||||
|
||||
if (tot_length > BSP_LCD_GetXSize()) {
|
||||
for (int i = 0; i < strlen(text); i++) {
|
||||
for (unsigned int i = 0; i < (unsigned int)strlen(text); i++) {
|
||||
if ((x_pos) > BSP_LCD_GetXSize() - (font->Width) * 2) {
|
||||
if (isalpha(text[i - 1]) && isalpha(text[i])) {
|
||||
BSP_LCD_DisplayChar(x_pos, y_pos, '-');
|
||||
BSP_LCD_DisplayChar(x_pos, y_pos, (uint8_t)'-');
|
||||
} else {
|
||||
BSP_LCD_DisplayChar(x_pos, y_pos, text[i]);
|
||||
BSP_LCD_DisplayChar(x_pos, y_pos, (uint8_t)text[i]);
|
||||
}
|
||||
x_pos = 0;
|
||||
y_pos += font->Height;
|
||||
continue;
|
||||
}
|
||||
BSP_LCD_DisplayChar(x_pos, y_pos, text[i]);
|
||||
BSP_LCD_DisplayChar(x_pos, y_pos, (uint8_t)text[i]);
|
||||
x_pos += font->Width;
|
||||
}
|
||||
return;
|
||||
}
|
||||
BSP_LCD_DisplayStringAt(x_pos, y_pos, text, LEFT_MODE);
|
||||
BSP_LCD_DisplayStringAt(x_pos, y_pos, (uint8_t*)text, LEFT_MODE);
|
||||
}
|
||||
|
||||
void lcd_draw_raw_img(const void* p_src, uint32_t x_pos, uint32_t y_pos, uint32_t x_size, uint32_t y_size, uint32_t color_mode) {
|
||||
LOG_INFO(TAG, "Displaying raw image: @x=%d, @y=%d, width=%d, height=%d", x_pos, y_pos, x_size, y_size);
|
||||
BSP_LCD_SelectLayer(0);
|
||||
uint32_t address = hLtdcHandler.LayerCfg[1].FBStartAdress + (((BSP_LCD_GetXSize() * y_pos) + x_pos) * (4));
|
||||
void* p_dst = (void*)address;
|
||||
|
||||
@@ -146,23 +153,49 @@ void lcd_draw_raw_img(const void* p_src, uint32_t x_pos, uint32_t y_pos, uint32_
|
||||
}
|
||||
|
||||
void lcd_draw_bmp_img(uint8_t* bmp_buff, uint32_t x_pos, uint32_t y_pos) {
|
||||
LOG_INFO(TAG, "Displaying BMP image: @x=%d, @y=%d", x_pos, y_pos);
|
||||
BSP_LCD_SelectLayer(0);
|
||||
BSP_LCD_DrawBitmap(x_pos, y_pos, bmp_buff);
|
||||
}
|
||||
|
||||
void lcd_draw_img_from_fs(const char* name, uint32_t x_pos, uint32_t y_pos) {
|
||||
LOG_INFO(TAG, "Displaying BMP image %s: @x=%d, @y=%d", name, x_pos, y_pos);
|
||||
BSP_LCD_SelectLayer(0);
|
||||
llfs_file_t* file = llfs_file_open(name);
|
||||
if (file != NULL) {
|
||||
BSP_LCD_DrawBitmap(x_pos, y_pos, (uint8_t*)file->data);
|
||||
return;
|
||||
}
|
||||
LOG_WARN(TAG, "File \"%s\" not found", file->name);
|
||||
LOG_WARN(TAG, "File \"%s\" not found", name);
|
||||
}
|
||||
|
||||
void lcd_clear(uint32_t color) {
|
||||
BSP_LCD_Clear(color);
|
||||
void lcd_clear_text(void) {
|
||||
LOG_INFO(TAG, "Clear text");
|
||||
BSP_LCD_SelectLayer(1);
|
||||
BSP_LCD_Clear(0);
|
||||
}
|
||||
|
||||
void lcd_clear_images(void) {
|
||||
LOG_INFO(TAG, "Clear images");
|
||||
BSP_LCD_SelectLayer(0);
|
||||
for (uint8_t i = 0; i < LCD_MAX_GIFS; i++) {
|
||||
if (gifs[i].src != NULL) {
|
||||
lcd_stop_gif(&gifs[i]);
|
||||
}
|
||||
}
|
||||
BSP_LCD_Clear(0);
|
||||
}
|
||||
|
||||
void lcd_stop_all_gifs(void) {
|
||||
for (uint8_t i = 0; i < LCD_MAX_GIFS; i++) {
|
||||
if (gifs[i].src != NULL) {
|
||||
lcd_stop_gif(&gifs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lcd_gif_t* lcd_draw_gif(uint8_t* src, size_t size, uint32_t x_pos, uint32_t y_pos) {
|
||||
BSP_LCD_SelectLayer(0);
|
||||
lcd_gif_t* gif;
|
||||
|
||||
// Get a free GIF slot
|
||||
@@ -174,6 +207,7 @@ lcd_gif_t* lcd_draw_gif(uint8_t* src, size_t size, uint32_t x_pos, uint32_t y_po
|
||||
// Open the GIF and reset slot values
|
||||
GIF_begin(&(gif->gif), GIF_PALETTE_RGB888);
|
||||
if (GIF_openRAM(&(gif->gif), src, (int)size, gif_draw_cb)) {
|
||||
LOG_INFO(TAG, "Draw GIF: @x=%d, @y=%d with size: %d", x_pos, y_pos, size);
|
||||
gif->src = src;
|
||||
gif->x_pos = x_pos;
|
||||
gif->y_pos = y_pos;
|
||||
@@ -193,6 +227,7 @@ lcd_gif_t* lcd_draw_gif(uint8_t* src, size_t size, uint32_t x_pos, uint32_t y_po
|
||||
}
|
||||
|
||||
lcd_gif_t* lcd_draw_gif_from_fs(const char* name, uint32_t x_pos, uint32_t y_pos) {
|
||||
BSP_LCD_SelectLayer(0);
|
||||
lcd_gif_t* gif;
|
||||
llfs_file_t* file;
|
||||
|
||||
@@ -202,7 +237,7 @@ lcd_gif_t* lcd_draw_gif_from_fs(const char* name, uint32_t x_pos, uint32_t y_pos
|
||||
LOG_WARN(TAG, "File \"%s\" not found", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_INFO(TAG, "Draw GIF %s", name);
|
||||
// Draw the GIF using the file data
|
||||
gif = lcd_draw_gif((uint8_t*)file->data, file->len, x_pos, y_pos);
|
||||
return gif;
|
||||
@@ -250,13 +285,14 @@ static inline void free_gif_slot(lcd_gif_t* gif) {
|
||||
* @param pDraw Pointer to the GIFDRAW struct
|
||||
*/
|
||||
static void gif_draw_cb(GIFDRAW* pDraw) {
|
||||
BSP_LCD_SelectLayer(0);
|
||||
lcd_gif_t* gif = (lcd_gif_t*)pDraw->pUser;
|
||||
uint8_t* palette = pDraw->pPalette24; // The RGB888 color palette
|
||||
uint8_t* p_src = pDraw->pPixels; // Source pixel pointer
|
||||
int y = pDraw->iY + pDraw->y; // Current line being drawn
|
||||
|
||||
// Calculate the destination address of the first pixel in the line
|
||||
uint32_t address = hLtdcHandler.LayerCfg[1].FBStartAdress + (((BSP_LCD_GetXSize() * gif->y_pos) + gif->x_pos) * 4)
|
||||
uint32_t address = hLtdcHandler.LayerCfg[0].FBStartAdress + (((BSP_LCD_GetXSize() * gif->y_pos) + gif->x_pos) * 4)
|
||||
+ (y * (BSP_LCD_GetXSize() * 4));
|
||||
|
||||
// Restore the background
|
||||
@@ -285,4 +321,4 @@ static void gif_draw_cb(GIFDRAW* pDraw) {
|
||||
// Draw the pixel
|
||||
((uint32_t *)address)[x] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#define LOGGER_LEVEL_WARN
|
||||
#include "llfs.h"
|
||||
#include "log.h"
|
||||
#include "llfs.h"
|
||||
|
||||
/**
|
||||
* @brief The maximum number of files that can be opened concurrently using the POSIX API
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
extern struct llfs_data_file* llfs_root;
|
||||
const char* TAG = "llfs";
|
||||
size_t file_count = 0;
|
||||
FILE* file_table[POSIX_MAX_FILES];
|
||||
static size_t file_count = 0; // Cache for the number of files in the filesystem
|
||||
static FILE* file_table[POSIX_MAX_FILES];
|
||||
|
||||
static int new_file_table_entry(void);
|
||||
static int free_file_table_entry(int file_id);
|
||||
@@ -41,6 +41,14 @@ int8_t llfs_init(void) {
|
||||
file_table[STDOUT_FILENO] = stdout;
|
||||
file_table[STDERR_FILENO] = stderr;
|
||||
|
||||
// Calculate the number of files in the filesystem and cache it
|
||||
const struct llfs_data_file* file = llfs_root;
|
||||
file_count = 0;
|
||||
while (file != NULL) {
|
||||
file_count++;
|
||||
file = file->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -130,13 +138,6 @@ llfs_file_t* llfs_next_file(void** mem, char* filter) {
|
||||
}
|
||||
|
||||
size_t llfs_file_count(void) {
|
||||
if (file_count == 0) {
|
||||
const struct llfs_data_file* file = llfs_root;
|
||||
while (file != NULL) {
|
||||
file_count++;
|
||||
file = file->next;
|
||||
}
|
||||
}
|
||||
return file_count;
|
||||
}
|
||||
|
||||
@@ -218,7 +219,7 @@ int _close(int file_id) {
|
||||
* @param len
|
||||
* @return
|
||||
*/
|
||||
int _read(int file_id, char* ptr, int len) {
|
||||
size_t _read(int file_id, char* ptr, int len) {
|
||||
FILE* stream;
|
||||
llfs_file_t* llfs_file;
|
||||
size_t bytes_read;
|
||||
@@ -256,7 +257,7 @@ int _read(int file_id, char* ptr, int len) {
|
||||
memcpy(ptr, llfs_file->data + stream->_offset, bytes_read);
|
||||
|
||||
stream->_offset += (off_t)bytes_read;
|
||||
return (int)bytes_read;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,7 +282,7 @@ int isatty(int file) {
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
int _lseek(int file, int ptr, int dir) {
|
||||
off_t _lseek(int file, int ptr, int dir) {
|
||||
FILE* stream;
|
||||
|
||||
if (file == STDIN_FILENO || file == STDOUT_FILENO || file == STDERR_FILENO) {
|
||||
@@ -310,7 +311,7 @@ int _lseek(int file, int ptr, int dir) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return stream->_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -409,8 +410,6 @@ static FILE* file_id_to_stream(int file_id) {
|
||||
return file_table[file_id];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check if a filename ends with a given extension
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
||||
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
@@ -29,7 +28,7 @@
|
||||
#include "log.h"
|
||||
#include "llfs.h"
|
||||
#include "lcd_api.h"
|
||||
#include "modbus-tcp.h"
|
||||
#include "tftp.h"
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
@@ -122,7 +121,7 @@ int main(void)
|
||||
BSP_QSPI_MemoryMappedMode();
|
||||
WRITE_REG(QUADSPI->LPTR, 0xFFF);
|
||||
|
||||
// Clear terminal
|
||||
/* Clear terminal */
|
||||
printf(CLEAR_SCREEN);
|
||||
|
||||
/* Initialize the LCD */
|
||||
@@ -131,9 +130,8 @@ int main(void)
|
||||
/* Initialize the filesystem */
|
||||
llfs_init();
|
||||
|
||||
/*initialize modbus*/
|
||||
modbus_init();
|
||||
|
||||
/* Initialize the tftp server */
|
||||
tftp_server_init();
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* Infinite loop */
|
||||
|
||||
323
project/Core/Src/tftp.c
Normal file
323
project/Core/Src/tftp.c
Normal file
@@ -0,0 +1,323 @@
|
||||
/**
|
||||
* @file tftp.c
|
||||
* @brief tftp server
|
||||
* @author Sander S.
|
||||
*/
|
||||
|
||||
#include "tftp.h"
|
||||
|
||||
#define VIRT_INDEX_TXT 0
|
||||
#define VIRT_IMAGE_BMP 1
|
||||
#define VIRT_IMAGE_GIF 2
|
||||
#define VIRT_TEXT_TXT 3
|
||||
#define MAX_VIRT_FILES 4
|
||||
|
||||
#define IMAGE_BUFFER_SIZE 81920
|
||||
|
||||
static const char* TAG = "tftp_server";
|
||||
|
||||
static tftp_custom_file_t virt_file[] = {{.name = "index.txt", .data = NULL, .len = 0, .offset = 0},
|
||||
{.name = "virtImage.bmp", .data = NULL, .len = 0, .offset = 0},
|
||||
{.name = "virtImage.gif", .data = NULL, .len = 0, .offset = 0},
|
||||
{.name = "virtText.txt", .data = NULL, .len = 0, .offset = 0}};
|
||||
|
||||
static int str_cat_str(char* dest, size_t dest_size, const char* src) {
|
||||
size_t dest_len = strlen(dest);
|
||||
size_t src_len = strlen(src);
|
||||
if (dest_len + src_len > dest_size) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(dest + dest_len, src, src_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int str_cat(char* dest, size_t dest_size, char c) {
|
||||
size_t dest_len = strlen(dest);
|
||||
if (dest_len + 1 > dest_size) {
|
||||
return -1;
|
||||
}
|
||||
dest[dest_len] = c;
|
||||
dest[dest_len + 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief tftp custom file functions to set the offset and read the data
|
||||
* @param[in,out] handle Custom file handles
|
||||
* @param[in] offset The offset to set
|
||||
* @param[in] whence The origin of the offset
|
||||
*/
|
||||
void tftp_custom_fseek(tftp_custom_file_t* handle, size_t offset, int whence) {
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
handle->offset = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
handle->offset += offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
break;
|
||||
}
|
||||
if (handle->offset > handle->len) {
|
||||
handle->offset = handle->len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief tftp custom file functions to read the data
|
||||
* auto rolling over the offset
|
||||
* if the bytes to read is bigger than the remaining bytes
|
||||
* it will read the remaining bytes and set the bytes to 0
|
||||
* @param[out] buf The buffer to write the data to
|
||||
* @param[in] bytes The number of bytes to read
|
||||
* @param[in,out] handle Custom file handles
|
||||
*/
|
||||
size_t tftp_custom_fread(void* buf, size_t bytes, tftp_custom_file_t* handle) {
|
||||
if (handle->offset + bytes > handle->len) {
|
||||
bytes = handle->len - handle->offset;
|
||||
}
|
||||
memcpy(buf, handle->data + handle->offset, bytes);
|
||||
handle->offset += bytes;
|
||||
((char*)buf)[bytes] = '\0';
|
||||
if (handle->offset > handle->len) {
|
||||
bytes = 0;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief tftp custom file functions to write the data
|
||||
* auto rolling over the offset
|
||||
*
|
||||
* @param buf The buffer to write the data to
|
||||
* @param bytes The number of bytes to write
|
||||
* @param handle The handle to the file to write to
|
||||
* @return The number of bytes written
|
||||
*/
|
||||
size_t tftp_custom_fwrite(const void* buf, size_t bytes, tftp_custom_file_t* handle) {
|
||||
if (handle->offset + bytes > handle->len) {
|
||||
bytes = handle->len - handle->offset;
|
||||
}
|
||||
memcpy(handle->data + handle->offset, buf, bytes);
|
||||
handle->offset += bytes;
|
||||
if (handle->offset > handle->len) {
|
||||
bytes = 0;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief tftp helper functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief This function is called when a file is opened
|
||||
* It should return a handle to the file or NULL if the file does not exist
|
||||
* The handle contains a ptr to or the actual file data or a virtual file
|
||||
*
|
||||
* @param fname The name of the file to open
|
||||
* @param mode Mode string from TFTP RFC
|
||||
* @param write Flag indicating read (0) or write (!= 0) access
|
||||
* @return void* File handle supplied to other functions
|
||||
*/
|
||||
void* tftp_open(const char* fname, const char* mode, uint8_t write) {
|
||||
LOG_INFO(TAG, "Opening %s", fname);
|
||||
|
||||
UNUSED(mode);
|
||||
|
||||
if (strcmp(fname, virt_file[VIRT_INDEX_TXT].name) == 0 && write == TFTP_READ) {
|
||||
tftp_custom_fseek(&virt_file[VIRT_INDEX_TXT], 0, SEEK_SET);
|
||||
return &virt_file[0];
|
||||
} else if (strcmp(fname, virt_file[VIRT_IMAGE_BMP].name) == 0 && write != TFTP_READ) {
|
||||
return &virt_file[VIRT_IMAGE_BMP];
|
||||
} else if (strcmp(fname, virt_file[VIRT_IMAGE_GIF].name) == 0 && write != TFTP_READ) {
|
||||
return &virt_file[VIRT_IMAGE_GIF];
|
||||
} else if (strcmp(fname, virt_file[VIRT_TEXT_TXT].name) == 0 && write != TFTP_READ) {
|
||||
return &virt_file[VIRT_TEXT_TXT];
|
||||
}
|
||||
|
||||
return fopen(fname, write ? "wb" : "rb");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function is called when a file is closed
|
||||
*
|
||||
* @param handle The handle to the file to close
|
||||
*/
|
||||
void tftp_close(void* handle) {
|
||||
LOG_INFO(TAG, "closing file");
|
||||
if (handle == NULL) {
|
||||
LOG_CRIT(TAG, "handle is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle == &virt_file[VIRT_IMAGE_BMP]) {
|
||||
lcd_clear_images();
|
||||
lcd_clear_text();
|
||||
lcd_draw_bmp_img((uint8_t*)virt_file[VIRT_IMAGE_BMP].data, 0, 0);
|
||||
}
|
||||
|
||||
if (handle == &virt_file[VIRT_IMAGE_GIF]) {
|
||||
lcd_clear_images();
|
||||
lcd_clear_text();
|
||||
lcd_draw_gif((uint8_t*)virt_file[VIRT_IMAGE_GIF].data, virt_file[VIRT_IMAGE_GIF].offset, 0, 0);
|
||||
}
|
||||
|
||||
if (handle == &virt_file[VIRT_TEXT_TXT]) {
|
||||
lcd_clear_images();
|
||||
lcd_clear_text();
|
||||
lcd_display_text((uint8_t*)virt_file[VIRT_TEXT_TXT].data, 0, 0, LCD_COLOR_WHITE, LCD_FONT16);
|
||||
}
|
||||
|
||||
if (handle == &virt_file[VIRT_INDEX_TXT] || handle == &virt_file[VIRT_IMAGE_BMP]
|
||||
|| handle == &virt_file[VIRT_IMAGE_GIF] || handle == &virt_file[VIRT_TEXT_TXT]) {
|
||||
((tftp_custom_file_t*)handle)->offset = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
fclose((FILE*)handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function is called when a file is read
|
||||
* The virtual files are filtered out first
|
||||
* then the file is trying to get read from the llfs
|
||||
*
|
||||
* @param handle File handle returned by open()
|
||||
* @param buf Target buffer to copy read data to
|
||||
* @param bytes Number of bytes to copy to buf
|
||||
* @return int >= 0: Success; < 0: Error
|
||||
*/
|
||||
int tftp_read(void* handle, void* buf, int bytes) {
|
||||
int ret = 0;
|
||||
LOG_INFO(TAG, "reading file");
|
||||
if (handle == NULL) {
|
||||
LOG_CRIT(TAG, "handle is null");
|
||||
return -1;
|
||||
}
|
||||
FILE* file = (FILE*)handle;
|
||||
|
||||
if ((tftp_custom_file_t*)file == &virt_file[VIRT_INDEX_TXT]) {
|
||||
ret = (int)tftp_custom_fread(buf, (size_t)bytes, (tftp_custom_file_t*)file);
|
||||
return ret;
|
||||
} else if ((tftp_custom_file_t*)file == &virt_file[VIRT_IMAGE_BMP]) {
|
||||
LOG_CRIT(TAG, "Exception: Trying to read a write only file");
|
||||
return -1;
|
||||
} else if ((tftp_custom_file_t*)file == &virt_file[VIRT_IMAGE_GIF]) {
|
||||
LOG_CRIT(TAG, "Exception: Trying to read a write only file");
|
||||
return -1;
|
||||
} else if ((tftp_custom_file_t*)file == &virt_file[VIRT_TEXT_TXT]) {
|
||||
LOG_CRIT(TAG, "Exception: Trying to read a write only file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = (int)fread(buf, sizeof(uint8_t), (size_t)bytes, file);
|
||||
if (ret <= 0) {
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function is called when a file is written
|
||||
*
|
||||
* @param handle File handle returned by open()
|
||||
* @param p PBUF adjusted such that payload pointer points to the beginning of write data.
|
||||
* In other words, TFTP headers are stripped off.
|
||||
* @return int >= 0: Success; < 0: Error
|
||||
*/
|
||||
int tftp_write(void* handle, struct pbuf* p) {
|
||||
LOG_INFO(TAG, "Writing file");
|
||||
tftp_custom_file_t* file = (tftp_custom_file_t*)handle;
|
||||
if (file == &virt_file[VIRT_IMAGE_BMP] || file == &virt_file[VIRT_IMAGE_GIF] || file == &virt_file[VIRT_TEXT_TXT]) {
|
||||
return (int)tftp_custom_fwrite(p->payload, (size_t)(p->len), file);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function creates the file list for index.txt
|
||||
*/
|
||||
void init_index(void) {
|
||||
size_t len = 0;
|
||||
// Add len of the virt files to the size
|
||||
for (int i = 0; i < MAX_VIRT_FILES; i++) {
|
||||
len += strlen(virt_file[i].name) + 1;
|
||||
}
|
||||
void* mem = NULL; // Pointer for internal use by the llfs library
|
||||
llfs_file_t* file;
|
||||
while ((file = llfs_next_file(&mem, NULL)) != NULL) {
|
||||
len += strlen(file->name) + 1;
|
||||
}
|
||||
len++; // +1 for the \0
|
||||
virt_file[VIRT_INDEX_TXT].data = calloc(len, sizeof(char));
|
||||
if (virt_file[VIRT_INDEX_TXT].data == NULL) {
|
||||
LOG_FATAL(TAG, "Could not allocate memory for index.txt");
|
||||
return;
|
||||
}
|
||||
virt_file[VIRT_INDEX_TXT].len = len;
|
||||
|
||||
for (int i = 0; i < MAX_VIRT_FILES; i++) {
|
||||
str_cat_str(virt_file[VIRT_INDEX_TXT].data, len, virt_file[i].name);
|
||||
str_cat(virt_file[VIRT_INDEX_TXT].data, len, '\n');
|
||||
}
|
||||
|
||||
mem = NULL;
|
||||
file = NULL;
|
||||
|
||||
while ((file = llfs_next_file(&mem, NULL)) != NULL) {
|
||||
str_cat_str(virt_file[VIRT_INDEX_TXT].data, len, file->name);
|
||||
str_cat(virt_file[VIRT_INDEX_TXT].data, len, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
struct tftp_context tftpContext_s = {.open = tftp_open, .close = tftp_close, .read = tftp_read, .write = tftp_write};
|
||||
|
||||
/**
|
||||
* @brief Initialize tftp server
|
||||
*/
|
||||
void tftp_server_init(void) {
|
||||
LOG_INFO(TAG, "Initializing tftp server");
|
||||
// init the index.txt virt_file
|
||||
init_index();
|
||||
LOG_DEBUG(TAG, "index.txt: %s", virt_file[VIRT_INDEX_TXT].data);
|
||||
// init the virtImage.raw virt_file with 80kb of ram
|
||||
virt_file[VIRT_IMAGE_BMP].data = calloc(IMAGE_BUFFER_SIZE, sizeof(char));
|
||||
if (virt_file[VIRT_IMAGE_BMP].data == NULL) {
|
||||
LOG_FATAL(TAG, "Could not allocate memory for virtImage.bmp/virtImage.gif");
|
||||
return;
|
||||
}
|
||||
virt_file[VIRT_IMAGE_BMP].len = IMAGE_BUFFER_SIZE;
|
||||
|
||||
virt_file[VIRT_IMAGE_GIF].data = virt_file[VIRT_IMAGE_BMP].data;
|
||||
virt_file[VIRT_IMAGE_GIF].len = virt_file[VIRT_IMAGE_BMP].len;
|
||||
|
||||
virt_file[VIRT_TEXT_TXT].data = virt_file[VIRT_IMAGE_BMP].data;
|
||||
virt_file[VIRT_TEXT_TXT].len = virt_file[VIRT_IMAGE_BMP].len;
|
||||
|
||||
// Init the tftp server
|
||||
if (tftp_init(&tftpContext_s) != ERR_OK) {
|
||||
LOG_FATAL(TAG, "Could not initialize tftp server");
|
||||
return;
|
||||
}
|
||||
LOG_INFO(TAG, "tftp server initialized successfully");
|
||||
}
|
||||
|
||||
void tftp_server_deinit(void) {
|
||||
LOG_INFO(TAG, "Deinitializing tftp server");
|
||||
tftp_cleanup();
|
||||
LOG_INFO(TAG, "tftp server deinitialized successfully");
|
||||
free(virt_file[VIRT_INDEX_TXT].data);
|
||||
virt_file[VIRT_INDEX_TXT].data = NULL;
|
||||
virt_file[VIRT_INDEX_TXT].len = 0;
|
||||
virt_file[VIRT_INDEX_TXT].offset = 0;
|
||||
free(virt_file[VIRT_IMAGE_BMP].data);
|
||||
virt_file[VIRT_IMAGE_BMP].data = NULL;
|
||||
virt_file[VIRT_IMAGE_BMP].len = 0;
|
||||
|
||||
virt_file[VIRT_IMAGE_GIF].data = NULL;
|
||||
virt_file[VIRT_IMAGE_GIF].len = 0;
|
||||
|
||||
virt_file[VIRT_TEXT_TXT].data = NULL;
|
||||
virt_file[VIRT_TEXT_TXT].len = 0;
|
||||
}
|
||||
40
tests/CMakeLists.txt
Normal file
40
tests/CMakeLists.txt
Normal file
@@ -0,0 +1,40 @@
|
||||
find_package(GTest REQUIRED)
|
||||
|
||||
# Third Party
|
||||
include_directories(${GTEST_INCLUDE_DIR})
|
||||
|
||||
link_directories(${GTEST_LIB_DIR})
|
||||
|
||||
# tests
|
||||
file(GLOB_RECURSE TEST_SOURCES "*.cpp" "*.c")
|
||||
add_executable(tests)
|
||||
|
||||
target_compile_definitions(tests
|
||||
PRIVATE
|
||||
"TESTING"
|
||||
)
|
||||
|
||||
target_sources(tests
|
||||
PRIVATE
|
||||
${TEST_SOURCES}
|
||||
../project/Core/Src/tftp.c
|
||||
)
|
||||
|
||||
target_compile_options(tests PRIVATE $<$<CONFIG:Debug>:
|
||||
-Wall -Wextra -pedantic-errors -Wconversion -Wsign-conversion
|
||||
>)
|
||||
target_link_libraries(tests
|
||||
PRIVATE
|
||||
gtest
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
target_include_directories(tests
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${PROJECT_BINARY_DIR}
|
||||
../project/Core/Inc/
|
||||
)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(tests)
|
||||
31
tests/mocs.c
Normal file
31
tests/mocs.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "tftp.h"
|
||||
|
||||
struct llfs_data_file llfs_root = {
|
||||
.data = NULL,
|
||||
.len = 0,
|
||||
.name = "root",
|
||||
.next = NULL,
|
||||
};
|
||||
|
||||
void tftp_cleanup(void) {
|
||||
|
||||
}
|
||||
uint32_t logger_get_timestamp(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tftp_init(struct tftp_context* context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lcd_display_text(uint8_t* text, uint16_t x_pos, uint16_t y_pos, uint32_t color, uint32_t bg_color, sFONT *font) {
|
||||
|
||||
}
|
||||
|
||||
void lcd_clear(uint32_t color) {
|
||||
|
||||
}
|
||||
|
||||
void lcd_draw_bmp_img(uint8_t* bmp_buff, uint32_t x_pos, uint32_t y_pos) {
|
||||
|
||||
}
|
||||
76
tests/tfpt_tests.cpp
Normal file
76
tests/tfpt_tests.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tftp.h"
|
||||
|
||||
tftp_custom_file_t file = {
|
||||
.data = (char*)"1234567890",
|
||||
.len = 11,
|
||||
.name = (char*)"test.txt",
|
||||
.ofset = 0
|
||||
};
|
||||
tftp_custom_file_t write_file = {
|
||||
.data = NULL,
|
||||
.len = 0,
|
||||
.name = (char*)"test.txt",
|
||||
.ofset = 0
|
||||
};
|
||||
|
||||
TEST(TFTP, custom_fseek)
|
||||
{
|
||||
tftp_custom_fseek(&file, 5, SEEK_SET);
|
||||
EXPECT_EQ(file.ofset, 5);
|
||||
tftp_custom_fseek(&file, 5, SEEK_CUR);
|
||||
EXPECT_EQ(file.ofset, 10);
|
||||
}
|
||||
|
||||
TEST(TFTP, custom_fread)
|
||||
{
|
||||
char buf[11];
|
||||
tftp_custom_fseek(&file, 0, SEEK_SET);
|
||||
size_t bytes = tftp_custom_fread(buf, 11, &file);
|
||||
EXPECT_EQ(bytes, 11);
|
||||
EXPECT_EQ(file.ofset, 11);
|
||||
EXPECT_EQ(memcmp(buf, "1234567890", 10), 0);
|
||||
|
||||
memset(buf, 0, 11);
|
||||
|
||||
tftp_custom_fseek(&file, 0, SEEK_SET);
|
||||
bytes = tftp_custom_fread(buf, 11, &file);
|
||||
EXPECT_EQ(bytes, 11);
|
||||
EXPECT_EQ(memcmp(buf, "1234567890", 10), 0);
|
||||
|
||||
memset(buf, 0, 11);
|
||||
|
||||
tftp_custom_fseek(&file, 0, SEEK_SET);
|
||||
bytes = tftp_custom_fread(buf, 5, &file);
|
||||
EXPECT_EQ(bytes, 5);
|
||||
EXPECT_EQ(memcmp(buf, "12345", 5), 0);
|
||||
|
||||
memset(buf, 0, 11);
|
||||
|
||||
bytes = tftp_custom_fread(buf, 5, &file);
|
||||
EXPECT_EQ(bytes, 5);
|
||||
EXPECT_EQ(memcmp(buf, "67890", 5), 0);
|
||||
}
|
||||
|
||||
TEST(TFTP, custom_fwrite) {
|
||||
write_file.data = (char*)malloc(21 * sizeof(char));
|
||||
write_file.len = 21;
|
||||
tftp_custom_fwrite("0987654321", 10, &write_file);
|
||||
EXPECT_EQ(write_file.ofset, 10);
|
||||
EXPECT_EQ(write_file.len, 21);
|
||||
EXPECT_EQ(memcmp(write_file.data, "0987654321", 10), 0);
|
||||
|
||||
tftp_custom_fwrite("1234567890", 10, &write_file);
|
||||
EXPECT_EQ(write_file.ofset, 20);
|
||||
EXPECT_EQ(write_file.len, 21);
|
||||
EXPECT_EQ(memcmp(write_file.data, "09876543211234567890", 20), 0);
|
||||
|
||||
free(write_file.data);
|
||||
write_file.data = NULL;
|
||||
write_file.len = 0;
|
||||
}
|
||||
45
tests/tftp_server.h
Normal file
45
tests/tftp_server.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct pbuf {
|
||||
struct pbuf *next;
|
||||
void *payload;
|
||||
uint16_t tot_len;
|
||||
uint16_t len;
|
||||
uint8_t type_internal;
|
||||
uint8_t flags;
|
||||
//LWIP_PBUF_REF_T ref;
|
||||
|
||||
uint8_t if_idx;
|
||||
};
|
||||
typedef void sFONT;
|
||||
|
||||
#define ERR_OK 0
|
||||
#define LCD_COLOR_BLACK 0
|
||||
#define LCD_COLOR_WHITE 1
|
||||
|
||||
#define LCD_FONT16 0
|
||||
|
||||
struct tftp_context {
|
||||
void* (*open)(const char* fname, const char* mode, uint8_t write);
|
||||
void (*close)(void* handle);
|
||||
int (*read)(void* handle, void* buf, int bytes);
|
||||
int (*write)(void* handle, struct pbuf* p);
|
||||
};
|
||||
|
||||
void tftp_cleanup(void);
|
||||
uint32_t logger_get_timestamp(void);
|
||||
int tftp_init(struct tftp_context* context);
|
||||
void lcd_display_text(uint8_t* text, uint16_t x_pos, uint16_t y_pos, uint32_t color, uint32_t bg_color, sFONT *font);
|
||||
void lcd_draw_bmp_img(uint8_t* bmp_buff, uint32_t x_pos, uint32_t y_pos);
|
||||
void lcd_clear(uint32_t color);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user