Hello, Khabrovites!
This is my first article and I have something to share. Perhaps my bike is not new and everyone uses this method, but once upon a time I was looking for a solution, I could not find it right away.
What are we talking about?
The task was to include files: HTML , JS , CSS ; without special training. It is also inconvenient to connect binary files (for example, pictures ) by converting them to HEX . Since I didn't want to convert to HEX or split into lines, I was looking for a way to connect the file to the program address space .
How it usually looks
Example, with line splitting:
const char text[] =
"<html>" "\r\n"
"<body>Text</body>" "\r\n"
"</html>";
Example, with HEX (more suitable for binary data):
const char text[] =
{
0x3C, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x0A, 0x3C,
0x62, 0x6F, 0x64, 0x79, 0x3E, 0x54, 0x65, 0x78,
0x74, 0x3C, 0x2F, 0x62, 0x6F, 0x64, 0x79, 0x3E,
0x0A, 0x3C, 0x2F, 0x68, 0x74, 0x6D, 0x6C, 0x3E,
0
};
I even saw this:
#define TEXT "<html>\r\n<body>Text</body>\r\n</html>"
const char text[] = TEXT;
#define .h Python. , \ . .
, , , :
extern const char text[];
, Assembler.
Arduino IDE
text.S, text.htm.
text.htm:
<html>
<body>Text</body>
</html>
text.S:
.global text
.section .rodata.myfiles
text:
.incbin "text.htm"
.byte 0
\0 , .
:
extern const char text[] PROGMEM;
void setup()
{
Serial.begin(115200);
Serial.println(text);
}
void loop() { }
, :
, - , .
AVR8, ESP8266 . , Flash 32 32 . , , :
.global text
.section .rodata.myfiles
.align 4
text:
.incbin "text.htm"
.byte 0
: .irom.text, .rodata.
STM32 32 , .
? , . :
.global text, text_size
.section .rodata.myfiles
text:
.incbin "text.htm"
text_end:
.byte 0
text_size:
.word (text_end - text)
:
extern const char text[] PROGMEM;
extern const uint16_t text_size PROGMEM;
, :
.macro addFile name file
.global \name, \name\()_size
// .align 4
\name:
.incbin "\file"
\name\()_end:
.byte 0
// .align 4
\name\()_size:
.word (\name\()_end - \name)
.endm
.section .rodata.myfiles
addFile text1 1.txt
addFile text2 2.txt
addFile text3 3.txt
:
#define ADD_FILE(name) \
extern const char name[] PROGMEM; \
extern const uint16_t name##_size PROGMEM;
ADD_FILE(text1);
ADD_FILE(text2);
ADD_FILE(text3);
void setup()
{
Serial.begin(115200);
Serial.println(text1);
Serial.println(text1_size);
Serial.println(text2);
Serial.println(text2_size);
Serial.println(text3);
Serial.println(text3_size);
}
void loop() { }
:
, .
, GNU toolchain
, Arduino. Arduino toolchain Atmel.
Makefile - .
STM32, . WEB- LWIP / HTTPD.
version.sh:
#!/bin/bash
# Version generator
# running script from pre-build
MAJOR=1
MINOR=0
cd "$(dirname $0)" &>/dev/null
FILE_VERSION="version.txt"
FILE_ASM="version.S"
BUILD=$(head -n1 "$FILE_VERSION" 2>/dev/null)
if [ -z "$BUILD" ]; then
BUILD=0
else
BUILD=$(expr $BUILD + 1)
fi
echo -n "$BUILD" >"$FILE_VERSION"
cat <<EOF >"$FILE_ASM"
/**
* no editing, automatically generated from version.sh
*/
.section .rodata
.global __version_major
.global __version_minor
.global __version_build
__version_major: .word $MAJOR
__version_minor: .word $MINOR
__version_build: .word $BUILD
.end
EOF
cd - &>/dev/null
exit 0
version.S version.txt .
Makefile pre-build:
#######################################
# pre-build script
#######################################
pre-build:
bash version.sh
all pre-build:
all: pre-build $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
printf macro.h:
extern const uint16_t __version_major;
extern const uint16_t __version_minor;
extern const uint16_t __version_build;
#define FMT_VER "%u.%u.%u"
#define FMT_VER_VAL __version_major, __version_minor, __version_build
HTTPD LWIP , HTTP. , fsdata.c. fsdata_custom.c, HTTPD_USE_CUSTOM_FSDATA.
fsdata_custom.c:
#include "lwip/apps/fs.h"
#include "lwip/def.h"
#include "fsdata.h"
#include "macro.h"
extern const struct fsdata_file __fs_root;
#define FS_ROOT &__fs_root
fsdata_make.S:
.macro addData name file mime
\name\():
.string "/\file\()"
\name\()_data:
.incbin "mime/\mime\().txt"
.incbin "\file\()"
\name\()_end:
.endm
.macro addFile name next
\name\()_file:
.word \next\()
.word \name\()
.word \name\()_data
.word \name\()_end - \name\()_data
.word 1
.endm
.section .rodata.fsdata
.global __fs_root
/* Load files */
addData __index_htm index.htm html
addData __styles_css styles.css css
addData __lib_js lib.js js
addData __ui_js ui.js js
addData __404_htm 404.htm 404
addData __favicon_ico img/favicon.ico ico
addData __logo_png img/logo.png png
/* FSDATA Table */
addFile __logo_png 0
addFile __favicon_ico __logo_png_file
addFile __404_htm __favicon_ico_file
addFile __ui_js __404_htm_file
addFile __lib_js __ui_js_file
addFile __styles_css __lib_js_file
__fs_root:
addFile __index_htm __styles_css_file
.end
, mime.
html.txt:
HTTP/1.1 200 OK Content-Type: text/html; charset=UTF-8 Connection: close
404.txt:
HTTP/1.1 404 Not found Content-Type: text/plain; charset=UTF-8 Connection: close
Note the blank line, which is required by the HTTP specification to mark the end of the header. Each line must end with CRLF (\ r \ n).
PS The project code is from a dilapidated chest, so the implementation could forget something to clarify.
At the end
I was looking for something useful in the article for a long time. I hope my experience is useful for a beginner and a guru.
Thank you for your attention, happy developments!