Merge branch 'main' into MQTT

This commit is contained in:
RobinVdB8
2023-11-23 09:55:50 +01:00
19 changed files with 10505 additions and 2667 deletions

View File

@@ -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

78
project/Core/Inc/tftp.h Normal file
View File

@@ -0,0 +1,78 @@
/**
* @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
#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

View File

@@ -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;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -29,6 +29,7 @@
#include "llfs.h"
#include "lcd_api.h"
#include "mug.h"
#include "tftp.h"
/* USER CODE END Includes */
@@ -121,7 +122,7 @@ int main(void)
BSP_QSPI_MemoryMappedMode();
WRITE_REG(QUADSPI->LPTR, 0xFFF);
// Clear terminal
/* Clear terminal */
printf(CLEAR_SCREEN);
/* Initialize the LCD */
@@ -130,6 +131,8 @@ int main(void)
/* Initialize the filesystem */
llfs_init();
/* Initialize the tftp server */
tftp_server_init();
/* USER CODE END 2 */
/* Infinite loop */

324
project/Core/Src/tftp.c Normal file
View File

@@ -0,0 +1,324 @@
/**
* @file tftp.c
* @brief tftp server
* @author Sander S.
*/
#define LOGGER_LEVEL_ALL
#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;
}